home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / general / modelers / nff / haines.doc < prev    next >
Internet Message Format  |  1992-12-02  |  95KB

  1. From markv@drizzle.UUCP Sun Sep  4 18:47:14 1988
  2. Path: seismo!uunet!husc6!mailrus!cornell!uw-beaver!uoregon!markv
  3. From: markv@uoregon.uoregon.edu (Mark VandeWettering)
  4. Newsgroups: comp.graphics
  5. Subject: Haine's NFF Package:    Part 01/01
  6. Message-ID: <2684@uoregon.uoregon.edu>
  7. Date: 4 Sep 88 22:47:14 GMT
  8. Reply-To: markv@drizzle.UUCP (Mark VandeWettering)
  9. Organization: University of Oregon, Computer Science, Eugene OR
  10. Lines: 2508
  11.  
  12.  
  13.  
  14. This is as it was posted to comp.graphics AGES ago.  Have fun.  If
  15. someone figures out why "gears" turns out funny on my raytracer, let me
  16. know, I am stumped.
  17.  
  18. # This is a shell archive.  Remove anything before this line,
  19. # then unpack it by saving it in a file and typing "sh file".
  20. #
  21. # Wrapped by eye!erich on November 17, 1987
  22. # Contents:  README makefile def.h lib.h lib.c
  23. #            balls.c gears.c mountain.c rings.c tetra.c tree.c
  24. echo x - README
  25. sed 's/^@//' > "README" <<'@//E*O*F README//'
  26. STANDARD PROCEDURAL DATABASES, by Eric Haines, 3D/Eye, Inc.
  27.  
  28. [Created while under contract to Hewlett-Packard FSD and HP Laboratories]
  29. Version 2.2, as of 11/17/87
  30.     address: 3D/Eye, Inc., 410 East Upland Road, Ithaca, NY 14850
  31.     e-mail: hpfcla!hpfcrs!eye!erich@hplabs.HP.COM
  32.  
  33. History
  34. -------
  35. This software package by Eric Haines is not copyrighted and can be used freely.
  36. Versions 1.0 to 1.5 released February to June, 1987 for testing.
  37. Version 2.0 released July, 1987.
  38. Version 2.1 released August, 1987 - corrected info on speed of the HP 320,
  39.     other minor changes to README.
  40. Version 2.2 released November, 1987 - shortened file names to <=12 characters,
  41.     procedure names to <= 32 characters, and ensured that all lines are <= 80
  42.     characters (including return character).
  43.  
  44. {This file uses tab characters worth 8 spaces}
  45.  
  46.  
  47. Introduction
  48. ------------
  49.  
  50.     This software is meant to act as a set of basic test images for ray tracing
  51. and hidden surface algorithms.  The programs generate databases of objects
  52. which are fairly familiar and "standard" to the graphics community, such as a
  53. fractal mountain, a tree, a recursively built tetrahedral structure, etc.  I
  54. created them originally for my own testing of a ray-tracer.  My hope is that
  55. these will be used by researchers to test algorithms.  In this way, research on
  56. algorithmic improvements can be compared on a more standard set of measures.
  57. At present, one researcher ray-traces a car, another a tree, and the question
  58. arises "How many cars to the tree?"  With these databases we may be comparing
  59. oranges and apples ("how many hypercubes to a timeshared VAX?"), but it sure
  60. beats comparing oranges and orangutans.
  61.  
  62.     Another use for these databases is to find how many vectors or polygons per
  63. second a particular machine can actually generate.  Talking with people
  64. at SIGGRAPH '86, I found that various vendors would say "well, they claim
  65. a rate of 5000 polygons/second, but their polygons are not our polygons".
  66. With these tests, their polygons are our polygons.  I admit a bias towards the
  67. structure of the HP-SRX ("Renaissance") display system and its display software
  68. "Starbase" in the way I structured the testing conditions (laid out later),
  69. but this comes fairly close to preliminary PHIGS+ standards.  For example,
  70. these databases are not kind to machines using the painter's algorithm, but I
  71. think this algorithm is inappropriate for good, general 3D modeling hardware.
  72. These databases do not use polygons where an intensity or color is given for
  73. each vertex, though such polygons are a feature of some machines (including
  74. the SRX).  They do include polygonal patches, where a normal is given for each
  75. vertex, as this feature seems fairly common.  Basically, if display hardware
  76. cannot provide 8 light sources, use of normals at vertices, specular shading,
  77. z-buffering, and perspective transformations, then I consider this machine
  78. somewhat ineffective for use in a 3D modeling environment (which is mostly all
  79. I care about--my personal bias).  If you do not, please tell me why!
  80.  
  81.  
  82. File Structure
  83. --------------
  84.  
  85.     Six different procedural database generators are included.  These were
  86. designed to span a fair range of primitives, modeling structures, lighting
  87. and surface conditions, background conditions, and other factors.  A complexity
  88. factor is provided within each program to control the size of the database
  89. generated.
  90.  
  91. This software package contains the following files:
  92.  
  93.     README - what you are now reading
  94.     makefile - used to make the programs (in HP-UX Unix)
  95.     def.h - some useful "C" definitions
  96.     lib.h - globals and library routine declarations
  97.     lib.c - library of routines
  98.     balls.c - fractal ball object generator
  99.     gears.c - 3D array of interlocking gears
  100.     mountain.c - fractal mountain and 4 glass ball generator
  101.     rings.c - pyramid of dodecahedral rings generator
  102.     tetra.c - recursive tetrahedra generator
  103.     tree.c - tree generator
  104.  
  105. The compiled and linked programs will output a database in ASCII to stdout
  106. containing viewing parameters, lighting conditions, material properties, and
  107. geometric information.  The data format is called the 'neutral file format'
  108. (or NFF) and is outlined in lib.c.  This format is meant to be minimal and
  109. (hopefully) easy to attach to a user-written filter program which will convert
  110. the output into a file format of your choosing.
  111.  
  112.     Either of two sets of primitives can be selected for output.  If
  113. OUTPUT_FORMAT is defined as OUTPUT_CURVES, the primitives are spheres, cones,
  114. cylinders, and polygons.  If OUTPUT_FORMAT is set to OUTPUT_PATCHES, the
  115. primitives are simply polygonal patches and polygons (i.e. all other primitives
  116. are polygonalized).  In this case OUTPUT_RESOLUTION is used to set the amount
  117. of polygonalization of non-polygonal primitives.  In general, OUTPUT_CURVES is
  118. used for ray-trace timing tests, and OUTPUT_PATCHES for hidden surface and
  119. other polygon-based algorithm timings.
  120.  
  121.     SIZE_FACTOR is used to control the overall size of the database.  Default
  122. values have been chosen such that the maximum number of primitives less than
  123. 10,000 is output.  One purpose of SIZE_FACTOR is to avoid limiting the uses of
  124. these databases.  Depending on the research being done and the computing
  125. facilities available, a larger or smaller number of primitives may be desired.
  126. SIZE_FACTOR can also be used to show how an algorithm's time changes as the
  127. complexity increases.
  128.  
  129.     Other parameters (for example, branching angles for "tree.c" and the
  130. fractal dimension in "mountain.c") are included for your own enjoyment, and so
  131. normally should not be changed if the database is used for timing tests.
  132.  
  133.     Note that light intensities, ambient components, etc. are not specified.
  134. These may be set however you prefer.  The thrust of these databases is the
  135. testing of rendering speeds, and so the actual color should not affect these
  136. calculations.  An ambient component should be used for all objects.  A simple
  137. formula for an intensity for each light and the ambient component is the
  138. following:  sqrt(# lights) / (# lights * 2).
  139.  
  140.  
  141. Database Analysis
  142. -----------------
  143.  
  144.     The databases "mountain", and "tetra" consist of primitives of about the
  145. same size in a localized cluster, "balls" and "tree" are more varied clusters,
  146. and "rings" and "gears" are somewhat space-filling for the eye rays.  Some
  147. other facts about these databases:
  148.  
  149.               balls      gears      mountain     rings       tetra        tree
  150.               -----      -----      --------     -----       -----        ----
  151. primitives      SP         P           PS         YSP          P          OSP
  152.     (where S=sphere, P=polygon, Y=cylinder, O=cone, in # of objects order)
  153. total prim.    7382       9345        8196        8401        4096        8191
  154. polys         1417K       9345        8960        874K        4096        852K
  155. rend. polys    707K       4448        5275        435K        2496        426K
  156. ave. poly      0.26      173.6        53.2        2.95        35.4        0.09
  157. vectors       4251K      55300       26880       2688K       12288       2621K
  158. rend. vectors 4251K      54692       26074       2688K       12288       2621K
  159. ave. vector    0.59        7.6        12.5        2.57        11.1        0.26
  160. ave. # edges   3.00       5.92        3.00        3.08        3.00        3.08
  161.  
  162. lights          3          5           1           3           1           7
  163. background      0%         7%         47%          0%         81%         35%
  164. specular       yes        yes         yes         yes          no          no
  165. transmitter     no        yes         yes          no          no          no
  166. ave tree size  1.79       3.02        3.71        2.19        1.00        1.00
  167. ave light rays 3.39       6.43        0.80        4.09        0.18        4.17
  168.  
  169.     "total prim." is the total number of ray-tracing primitives (polygons,
  170. spheres, cylinders and cones) in the scene.  The number of polygons and vectors
  171. generated is a function of the OUTPUT_RESOLUTION.  The default value for this
  172. parameter is 4 for all databases.
  173.  
  174.     "polys" is the total number of polygons and polygonal patches generated
  175. when using OUTPUT_PATCHES.  "rend. polys" is the number of polygons actually
  176. sent to the z-buffer (i.e. not culled and not fully clipped).  "ave. poly" is
  177. the average rendered polygon size in pixels for a 512 x 512 resolution.  Note
  178. that this size is the average of the number of pixels put on the screen by all
  179. unculled, not fully clipped polygons.  Culled polygons are not counted, nor are
  180. pieces of polygons which are off-screen (clipped).  For this statistic, all
  181. transparent objects are considered opaque.  The area was calculated directly
  182. from the exact transformed vertices, not from the screen.  Note that in
  183. practice there usually are more pixels per polygon actually rendered, mostly
  184. due to the polygon edges being fully rendered.  It is because of this machine
  185. dependency that the purely geometric area is given.
  186.  
  187.     "vectors" is the total number of vectors generated.  "rend. vector" is the
  188. number of vectors which were not fully clipped off the screen (note that no
  189. culling takes place in vector testing).  "ave. vector" is similar to "ave.
  190. poly", being the average length of all rendered vectors in pixels.  Note that
  191. culling is not performed for vectors.  Again, the actual number of pixels
  192. rendered is machine dependent and could be different than this average vector
  193. length.
  194.  
  195.     "lights" is simply the number of lights in a scene.  "background" is the
  196. percentage of background color (empty space) seen directly by the eye.  Note
  197. that any information in units of pixels is view dependent, and so is for the
  198. view specified.  "ave tree size" is the average number of rays in a ray tree.
  199. "ave light rays" is the average number of shadow testing rays formed per tree
  200. (note that if a surface is facing away from a light, or the background is hit,
  201. a light ray is not formed).  "K" means exactly 1000 (not 1024).
  202.  
  203.  
  204. Testing Procedures
  205. ------------------
  206.  
  207. Below are listed the requirements for testing various algorithms.  These test
  208. conditions should be realizable by most systems, and are meant to represent a
  209. common mode of operation for each algorithm.  Special features which the
  210. hardware supports (or standard features which it lacks) should be noted with
  211. the statistics.
  212.  
  213.  
  214. Hardware Vector Testing:
  215.  
  216.     1)  Two separate tests should be performed.  One test should be done at
  217.     a resolution of 512 x 512.  The second test should be done at the
  218.     maximum square resolution representable on the screen (e.g. the
  219.     HP SRX's resolution is 1280 x 1024, so run the tests at 1024 x 1024).
  220.     The first test is done so that the same sized polygons are used in
  221.     tests.  The second test is done to test the display hardware using a
  222.     more commonly used image resolution.
  223.  
  224.     2)  At least 24 bit planes should be used for color rendering, if
  225.     available.  If not, this should be noted and the best mapping mode
  226.     available should be used.
  227.  
  228.     3)  Vectors should be flat-shaded, with no hidden line removal performed
  229.     and no depth-cueing (but note these features if available).
  230.  
  231.     4)  The largest unit of display is the polygon.  This means that no
  232.     queueing of edge lists or optimization of move/draw commands can be
  233.     performed by the user.  All polygons must be rendered.  This will mean
  234.     that many edges will be drawn twice (since they are shared by
  235.     polygons).
  236.  
  237.     5)  Timings will consist of only the time spent on the polygon draw calls,
  238.     including the overhead of calling the display routine itself.  This
  239.     goal can most easily be realized by timing two versions of the testing
  240.     program.  One version reads the database and displays the results
  241.     normally.  The second version has all the system supplied vector
  242.     drawing commands removed, and so will output no vectors.  We can
  243.     determine the time spent actually displaying vectors by taking the
  244.     difference of these two timings.  This time divided by the total number
  245.     of vectors created by the database (listed in the table as "vectors")
  246.     is the vector rate for the database.
  247.  
  248.     6)  Two separate rates should be calculated from the average rates
  249.     computed.  One is the display rate, which is the average of the gears,
  250.     mountain, and tetra databases; the other is the throughput rate, which
  251.     is the average of the balls, rings, and tree databases.  The difference
  252.     is that the databases used to calculate the display rate are more
  253.     realistic as far as average polygon size presently used in hidden
  254.     surface comparisons.  This rate should better reflect the day-to-day
  255.     performance expected of a machine.  The databases for the throughput
  256.     rate are characterized by very small polygons, and so will reflect the
  257.     fastest speed of the hardware, as the effort to actually put the
  258.     vectors on the screen should be minimal.
  259.  
  260.  
  261. Hardware Shaded Hidden Surface Testing:
  262.  
  263.     1)  As in hardware vector testing, two tests should be performed at the
  264.     two resolutions.  A display and throughput rate should be calculated.
  265.  
  266.     2)  All polygons in the databases are guaranteed to be planar.  Polygons
  267.     do not interpenetrate, and only in "rings.c" does cyclical overlapping
  268.     occur.  The first three points of a polygon always form an angle less
  269.     than 180 degrees, and so can be used to compute the surface normal.
  270.     This computation should be done by the hardware if possible (and if
  271.     not, should be noted as such).
  272.  
  273.     3)  Polygons are one-sided for all databases (though transparent objects
  274.     may have to be treated as two-sided), and so the hardware can use the
  275.     surface normal to cull.  It is not valid to cull (or perform any other
  276.     clipping or shading function) using the software.
  277.  
  278.     4)  Polygons should be displayed using hidden surface rendering methods.
  279.     No software sorting or other irregular manipulation of the data is
  280.     allowed: the polygons should be rendered on a first-come first-served
  281.     basis.
  282.  
  283.     5)  Up to seven light sources and an ambient contribution are used in the
  284.     databases.  If the hardware does not have this many, note it and test
  285.     with the first few lights.  Lights do not fall off with distance.
  286.     Shadowing is not performed (though it's an incredible feature if it
  287.     is).
  288.  
  289.     6)  Light sources are positional.  If unavailable, assign the directional
  290.     lights a vector given by the light position and the viewing "lookat"
  291.     position.
  292.  
  293.     7)    Specular highlighting should be performed for surfaces with a specular
  294.     component.  The simple Phong distribution model is sufficient (though
  295.     note improvements, if any).
  296.  
  297.     8)  Polygonal patches should have smooth shading, if available.  In this
  298.     case a Gouraud interpolation of the colors calculated at the vertices
  299.     is the simplest algorithm allowed (again, note any more advanced
  300.     algorithms).
  301.  
  302.     9)  Transparency should be used if available, and the technique explained.
  303.     For example, the HP SRX uses "screen door" transparency, with a fill
  304.     pattern of a checkerboard.  Transparent objects are then rendered by
  305.     filling every other pixel.
  306.  
  307.     10) Overflow of color calculations is not guaranteed for these databases.
  308.     As such, this should be handled by scaling to the maximum color
  309.     contribution (e.g. r/g/b of 2 4 5 gets scaled to 0.4 0.8 1.0) if
  310.     available.  If not, simple clamping should be used and noted (e.g. an
  311.     r/g/b of 0.8 1.1 1.5 is output as 0.8 1.0 1.0).
  312.  
  313.     11) As in vector testing, timings should be done only for the actual
  314.     polygon rendering routines.  This means such costs as changing fill
  315.     color, vertex format, or other state record information is not counted
  316.     in the timing performed, but rather a flat-out speed test of the
  317.     shaded polygon rate is made.
  318.  
  319.  
  320. Other Hardware Tests:
  321.  
  322.     A number of tests which could also be performed, but that I have ignored
  323. for now, include the following:
  324.  
  325.     1)  Flat-shaded rendering: render polygons using only their fill colors.
  326.     Such renderings will look like mush, but would be useful for showing
  327.     the difference in speed for a flat-shade vs. shaded rendering.
  328.  
  329.     2)  Hidden-line rendering: render flat shaded polygons the same color as
  330.         the background, with edges a different color.  Culling can be used to
  331.     eliminate polygons.
  332.  
  333.     3)  No polypatch rendering: render polygonal patches but ignore their
  334.     normal per vertex values (i.e. render them as simple flat polygons).
  335.     Again, useful to show the time cost of using normals/vertex.
  336.     Pointless, of course, for the databases without polygonal patches.
  337.  
  338.     4)  No specular rendering: render without specular highlighting.  Useless
  339.     for the databases without specular highlighting.
  340.  
  341.     5)  Total cull and clip rendering: render with the lookat direction
  342.     reversed.  Change the at vector to be equal to ( 2*from - at ) and up
  343.     to be -up.  No objects will be displayed.  This test gives a sense of
  344.     the speed of the cull and clip hardware.
  345.  
  346.     Such a full battery of tests would yield some interesting results.
  347. Hardware could be compared in a large number of categories, allowing users to
  348. be able to select equipment optimized for their application.  I feel the most
  349. important rates are the vectors/second and the fully rendered polygons/second,
  350. as these two display methods bracket the gamut of realism offered by standard
  351. display hardware.
  352.  
  353.  
  354. Ray-Tracer Testing:
  355.  
  356.     1)  Assume the same conditions apply as in the shaded hidden surface
  357.     testing outline, except as noted below.  Note that the non-polygon
  358.     (OUTPUT_CURVES) format should be used for ray-tracing tests.
  359.  
  360.     2)  All opaque (non-transmitting) primitives can be considered one-sided
  361.     for rendering purposes, similar to how polygons were considered one-
  362.     -sided for hidden surface testing.  Only the outside of sphere, cone,
  363.     and cylinder primitives are viewed in the databases.
  364.  
  365.     3)  Render at a resolution of 512 x 512 pixels, shooting rays at the
  366.     corners (meaning that at least 513 x 513 eye rays will be created).
  367.     The four corner contributions are averaged to arrive at a pixel
  368.     value.  If this is not done, note this fact.  No pixel subdivision
  369.     is performed.
  370.  
  371.     4)  The maximum tree depth is 5 (where the eye ray is of depth 1).
  372.  
  373.     5)  All rays hitting specular and transmitting objects spawn reflection
  374.     rays, unless the maximum ray depth was reached by the spawning ray.
  375.     No adaptive tree depth cutoff is allowed; that is, all rays must be
  376.     spawned (adaptive tree depth is a proven time saver and is also
  377.     dependent on the color model used).
  378.  
  379.     6)  All rays hitting transmitting objects spawn refraction rays, unless
  380.     the maximum ray depth was reached.  Transmitting rays should be
  381.     refracted (i.e. should not pass straight through an object).  If total
  382.     internal reflection of a ray occurs, then only a reflection ray is
  383.     generated at this node.
  384.  
  385.     7)  Assume no hierarchy is given with the database (for example, color
  386.     change cannot be used to signal a clustering).
  387.  
  388.     8)  Timing costs should be separated into at least two areas: preprocessing
  389.     and ray-tracing.  Preprocessing includes all time spent initializing,
  390.     reading the database, and creating data structures needed to ray-trace.
  391.     Preprocessing should be all the constant cost operations--those that
  392.     do not change with the resolution of the image.  Ray-tracing is the
  393.     time actually spent tracing the rays (i.e. everything that is not
  394.     preprocessing).
  395.  
  396.     9)  Other timing costs which would be of interest is a breakdown of
  397.     times spent in the preprocessing and for actual ray-tracing.  Examples
  398.     include time spent creating a hierarchy, octree, or item buffer, and
  399.     times spent on intersection the various primitives and on calculating
  400.     the color.
  401.  
  402.     One major complaint with simple timing tests is that they tell little about
  403. the actual algorithm performance per se.  One partial remedy to this problem is
  404. to also include in statistics the number of object intersection tests performed
  405. and the number of hits recorded.  This information is useful for comparing
  406. techniques.  One example would be comparing various automatic hierarchy
  407. algorithms by using these statistics.
  408.  
  409.     Other information should be included in ray-trace timing results that is
  410. often overlooked or ignored.  Some basic information about the system
  411. configuration should be made: average speed of machine in terms of mips,
  412. Mflops, or Vaxen (i.e. the HP 320 is about 75 Kflops (single), which is about
  413. 30% of the speed of a VAX 11/780 FPA running vms 4.1, which is rated at 250
  414. Kflops.  However, some HP hardware engineer told me that the HP 320 is twice
  415. the speed of an 11/780 - it is unclear if this was incorrect.  He might be
  416. right about overall machine speed in MIPS, for example); physical memory
  417. size (i.e. 6 Mbytes); special hardware such as a floating point accelerator or
  418. array processor, if different than the standard machine; system costs during
  419. tests (i.e. single user mode vs. time-share with other heavy users vs. serious
  420. operating system overhead); operating system (i.e. HP-UX version 5.2); and
  421. language used (i.e. optimized "C", single point precision in general).
  422.  
  423.  
  424. Timings
  425. -------
  426.  
  427. Rendering time for test set on HP-320SRX:
  428.  
  429.                    Vector (seconds)           |         Z-buffer (seconds)
  430.               512 x 512     1024 x 1024       |     512 x 512       1024 x 1024
  431. balls           369.03          380.32        |       284.52            320.93
  432. gears             6.19            5.26        |         6.84              4.82
  433. mountain          4.83            4.37        |         3.84              2.88
  434. rings           232.28          243.65        |       181.28            202.11
  435. tetra             2.24            2.08        |         1.85              1.40
  436. tree            226.54          236.44        |       176.17            196.68
  437.  
  438.  
  439. Calculated performance of test set on HP-320SRX:
  440.  
  441.                Vector (vectors/second)        |       Z-buffer (polys/second)
  442.               512 x 512     1024 x 1024       |     512 x 512       1024 x 1024
  443. gears            8937           10513         |        1365              1940
  444. mountain         5563            6154         |        2331              3115
  445. tetra            5496            5908         |        2216              2925
  446. -------------------------------------------------------------------------------
  447. Display average  6665            7525         |        1971              2660
  448. (display average vector length for 512x512 is 10.4 pixels, 1024x1024 is  20.8)
  449. (display average polygon size  for 512x512 is 87.4 pixels, 1024x1024 is 349.6)
  450.  
  451.  
  452.                Vector (vectors/second)        |       Z-buffer (polys/second)
  453.               512 x 512     1024 x 1024       |     512 x 512       1024 x 1024
  454. balls           11521           11179         |        4981              4416
  455. rings           11572           11032         |        4819              4322
  456. tree            11569           11084         |        4835              4331
  457. -------------------------------------------------------------------------------
  458. Throughput ave. 11554           11098         |        4878              4356
  459. (throughput ave. vector length for 512x512 is 1.1 pixels, 1024x1024 is 2.3)
  460. (throughput ave. polygon size  for 512x512 is 1.1 pixels, 1024x1024 is 4.4)
  461.  
  462.  
  463. The above times are computed from the average of 5 runs for each database.
  464. The timing increment is 0.02 seconds (50 Hz).  Variance over the runs was
  465. quite small.  Note that many of the tests at maximum square resolution
  466. (1024 x 1024) for the hidden surface timings are faster than those for the low
  467. resolution (512 x 512).  The HP-320SRX is a workstation with 6 MByte memory and
  468. floating point accelerator.  24 bit color was used for display, and the full
  469. screen resolution is 1280 x 1024.
  470.  
  471.  
  472. Rendering time of the ray-traced test set on HP-320SRX (512 x 512 pixels):
  473.  
  474.            Setup    Ray-Tracing  |  Polygon    Sphere     Cyl/Cone    Bounding
  475.               (hr:min:sec)       |   Tests      Tests       Tests    Vol. Tests
  476. -------------------------------------------------------------------------------
  477. balls      13:24      4:36:48    |   1084K      6253K         0        41219K
  478. gears      13:49     10:32:51    |  12908K        0           0        92071K
  479. mountain   11:46      2:59:58    |   3807K      4193K         0        31720K
  480. rings      31:56     13:30:40    |   1203K      5393K      15817K      94388K
  481. tetra       4:04        15:40    |    342K        0           0         1491K
  482. tree        7:37      3:43:23    |   1199K      2218K        973K      20258K
  483.  
  484. A typical set of ray tracing intersection statistics for the tetra database is:
  485.  
  486. [these statistics should be the same for all users]
  487.   image size: 512 x 512
  488.   total number of pixels: 262144            [ 512 x 512 ]
  489.   total number of trees generated: 263169        [ 513 x 513 ]
  490.   total number of tree rays generated: 263169        [ no rays spawned ]
  491.   number of eye rays which hit background: 213219    [ 81% ]
  492.   average number of rays per tree: 1.000000
  493.   average number of rays per pixel: 1.003910
  494.   total number of shadow rays generated: 46262
  495.  
  496. [these tests vary depending on the ray-tracing algorithm used]
  497. Ray/Item Tests Performed:
  498.   Polygonal:       342149 (     55495 hit -  16.2 % )
  499.   Bounding Box:   1491181 (    351754 hit -  23.6 % )
  500.   Total:          1833330 (    407249 hit -  22.2 % )
  501.  
  502.     Setup times are dominated by a verbose data format which causes a massive
  503. (usually tenfold) increase in size from the NFF file format to our in-house
  504. format.  It should also be noted that for my sphere and bounding volume tests
  505. there are more tests than are strictly needed.  This is because I require each
  506. light to be attached to an object (a sphere), which leads to extra testing in
  507. both of these categories.
  508.  
  509.     For what it's worth, my ray-tracer is based on hierarchical bounding boxes
  510. generated using Goldsmith & Salmon's automatic hierarchy method (see IEEE CG&A
  511. May 1987) and uses an item buffer (no light buffer yet) and shadow coherency.
  512. Something to think about is how the octree, SEADS, and other such algorithms
  513. perform when the background polygon dimensions are changed (thus changing the
  514. size of the outermost enclosing box, which changes the octree encoding of the
  515. environment).  Same question with the effects of moving light source positions
  516. along the line defined by the light and "lookat" positions.
  517.  
  518.  
  519. Future Work
  520. -----------
  521.  
  522.     These databases are not meant to be the ultimate in standards, but are
  523. presented as a first attempt at providing somewhat representative modelled
  524. environments.  A number of extensions to the file format should be provided
  525. someday, along with new database generators which use them.  The present
  526. databases do not contain holed polygons, spline patches, polygonal mesh or
  527. triangular strip data structures, or other proposed PHIGS+ extensions.
  528. Modeling matrices are not output, and CSG combined primitives are not included.
  529.  
  530.     As far as database geometry is concerned, most scenes have a preponderance
  531. of small primitives, and in general very few objects ever get clipped.  If you
  532. find that these databases do not reflect the type of environments you render,
  533. please write and explain why (or better yet, write one or more programs that
  534. will generate your "typical" environments--maybe it will get put in the next
  535. release).
  536.  
  537.  
  538. Acknowledgements
  539. ----------------
  540.  
  541.     I originally heard of this idea from Don Greenberg back in 1984.  Some time
  542. earlier he and Ed Catmull had talked over coming up with some standard
  543. databases for testing algorithmic claims, and to them must go the credit for
  544. the basic concept.  Many thanks to the reviewers, listed alphabetically:  Kells
  545. Elmquist, Jeff Goldsmith, Donald Greenberg, Susan Spach, Rick Speer, John
  546. Wallace, and Louise Watson.  Other people who have freely offered their ideas
  547. and opinions on this project include Brian Barsky, Andrew Glassner, Roy Hall,
  548. Chip Hatfield, Tim Kay, John Recker, Paul Strauss, and Chan Verbeck.  These
  549. names are mentioned mostly as a listing of people interested in this idea.
  550. They do not necessarily agree (and in some cases strongly disagree) with the
  551. validity of the concept or the choice of databases.
  552.  
  553.     Your comments and suggestions on these databases are appreciated.  Please
  554. send any timing results for software and hardware which you test.
  555. @//E*O*F README//
  556. chmod u=rw,g=r,o= README
  557. echo x - makefile
  558. sed 's/^@//' > "makefile" <<'@//E*O*F makefile//'
  559. # makefile for standard procedural databases
  560. # Version:  2.2 (11/17/87)
  561. # Author:  Eric Haines, 3D/Eye, Inc.
  562. #   Works on the HP 300 machines--probably needs to be modified to your system
  563.  
  564. # cc    = C compiler
  565. #    -c    compile only, do not try to link
  566.  
  567. CC=cc -c
  568. INC=def.h lib.h
  569. BASELIB=-lm -lmalloc
  570.  
  571. all:        balls gears mountain rings tetra tree
  572.  
  573. lib.o:        $(INC) lib.c
  574.         $(CC) lib.c
  575.  
  576. balls:        lib.o balls.o
  577.         cc -o balls balls.o lib.o $(BASELIB)
  578.  
  579. balls.o:    $(INC) balls.c
  580.         $(CC) balls.c
  581.  
  582. gears:        lib.o gears.o
  583.         cc -o gears gears.o lib.o $(BASELIB)
  584.  
  585. gears.o:    $(INC) gears.c
  586.         $(CC) gears.c
  587.  
  588. mountain:    lib.o mountain.o
  589.         cc -o mountain mountain.o lib.o $(BASELIB)
  590.  
  591. mountain.o:    $(INC) mountain.c
  592.         $(CC) mountain.c
  593.  
  594. rings:        lib.o rings.o
  595.         cc -o rings rings.o lib.o $(BASELIB)
  596.  
  597. rings.o:    $(INC) rings.c
  598.         $(CC) rings.c
  599.  
  600. tetra:        lib.o tetra.o
  601.         cc -o tetra tetra.o lib.o $(BASELIB)
  602.  
  603. tetra.o:    $(INC) tetra.c
  604.         $(CC) tetra.c
  605.  
  606. tree:        lib.o tree.o
  607.         cc -o tree tree.o lib.o $(BASELIB)
  608.  
  609. tree.o:        $(INC) tree.c
  610.         $(CC) tree.c
  611. @//E*O*F makefile//
  612. chmod u=rw,g=r,o= makefile
  613. echo x - def.h
  614. sed 's/^@//' > "def.h" <<'@//E*O*F def.h//'
  615. /*
  616.  * def.h contains some useful definitions for "C" programs.
  617.  *
  618.  * Version:  2.2 (11/17/87)
  619.  * Author:  Eric Haines, 3D/Eye, Inc.
  620.  */
  621.  
  622. #define EPSILON        5.0e-6
  623.  
  624. #ifndef FALSE
  625. #define    FALSE    0
  626. #endif
  627.  
  628. #ifndef NULL
  629. #define    NULL    0
  630. #endif
  631.  
  632. #ifndef TRUE
  633. #define    TRUE    1
  634. #endif
  635.  
  636. #ifndef PI
  637. #define    PI    3.141592653589793
  638. #endif
  639.  
  640.  
  641. typedef    double        MATRIX[4][4] ;    /* row major form */
  642.  
  643. typedef    struct {
  644.     double    x ;
  645.     double    y ;
  646.     double    z ;
  647.     double    w ;
  648. } COORD4, *COORD4_P ;
  649.  
  650.  
  651. #define ABSOLUTE(A)        ( (A) < 0 ? -(A) : (A) )
  652. #define    FRACTION(A)        ( (A) - (long)(A) )
  653. #define    MAX(A,B)        ( (A) > (B) ? (A) : (B) )
  654. #define MAX3(A,B,C)        ( MAX( MAX( A,B ), C ) )
  655. #define    MIN(A,B)        ( (A) < (B) ? (A) : (B) )
  656. #define MIN3(A,B,C)        ( MIN( MIN( A,B ), C ) )
  657. #define SQR(A)            ( (A) * (A) )
  658.  
  659. #define ADD2_COORD(r,a)        { (r).x += (a).x; (r).y += (a).y;\
  660.                   (r).z += (a).z; }
  661. #define ADD3_COORD(r,a,b)    { (r).x = (a).x + (b).x;\
  662.                   (r).y = (a).y + (b).y;\
  663.                   (r).z = (a).z + (b).z; }
  664. #define COPY_COORD(r,a)        { (r).x = (a).x; (r).y = (a).y; (r).z = (a).z;}
  665. #define COPY_COORD4(r,a)    { (r).x = (a).x; (r).y = (a).y; (r).z = (a).z;\
  666.                   (r).w = (a).w; }
  667. #define CROSS(r,a,b)        { (r).x = (a).y * (b).z - (a).z * (b).y;\
  668.                   (r).y = (a).z * (b).x - (a).x * (b).z;\
  669.                   (r).z = (a).x * (b).y - (a).y * (b).x; }
  670. #define DOT_PRODUCT(a,b)    ( (a).x * (b).x +\
  671.                   (a).y * (b).y +\
  672.                   (a).z * (b).z )
  673. #define SET_COORD(r,a,b,c)    { (r).x = (a); (r).y = (b); (r).z = (c); }
  674. #define SET_COORD4(r,a,b,c,d)    { (r).x = (a); (r).y = (b); (r).z = (c);\
  675.                   (r).w = (d); }
  676. #define SUB2_COORD(r,a)        { (r).x -= (a).x; (r).y -= (a).y;\
  677.                   (r).z -= (a).z; }
  678. #define SUB3_COORD(r,a,b)    { (r).x = (a).x - (b).x;\
  679.                   (r).y = (a).y - (b).y;\
  680.                   (r).z = (a).z - (b).z; }
  681. @//E*O*F def.h//
  682. chmod u=rw,g=r,o= def.h
  683. echo x - lib.h
  684. sed 's/^@//' > "lib.h" <<'@//E*O*F lib.h//'
  685. /*
  686.  * lib.h - vector library definitions
  687.  *
  688.  * Version:  2.2 (11/17/87)
  689.  * Author:  Eric Haines, 3D/Eye, Inc.
  690.  */
  691.  
  692. #define    X_AXIS    0
  693. #define    Y_AXIS    1
  694. #define    Z_AXIS    2
  695.  
  696. /* Output library definitions */
  697. #define OUTPUT_CURVES        0    /* true curve output */
  698. #define OUTPUT_PATCHES        1    /* polygonal patches output */
  699.  
  700. #define OUTPUT_RESOLUTION    4    /* amount of polygonalization */
  701.  
  702. double    lib_normalize_coord3() ;
  703. double    lib_gauss_rand() ;
  704. @//E*O*F lib.h//
  705. chmod u=rw,g=r,o= lib.h
  706. echo x - lib.c
  707. sed 's/^@//' > "lib.c" <<'@//E*O*F lib.c//'
  708. /*
  709.  * lib.c - a library of vector operations, a random number generator, and
  710.  *     object output routines.
  711.  *
  712.  * Version:  2.2 (11/17/87)
  713.  * Author:  Eric Haines, 3D/Eye, Inc.
  714.  */
  715.  
  716. #include <stdio.h>
  717. #include <math.h>
  718. #include <memory.h>
  719. #include "def.h"
  720. #include "lib.h"
  721.  
  722.  
  723. /*
  724.  * Normalize the vector (X,Y,Z) so that X*X + Y*Y + Z*Z = 1.
  725.  *
  726.  * The normalization divisor is returned.  If the divisor is zero, no
  727.  * normalization occurs.
  728.  *
  729.  */
  730. double    lib_normalize_coord3( cvec )
  731. COORD4    *cvec;
  732. {
  733.     double divisor;
  734.  
  735.  
  736.     divisor = sqrt( (double)DOT_PRODUCT( (*cvec), (*cvec) ) ) ;
  737.  
  738.     if ( divisor != 0.0 ) {
  739.     cvec->x /= divisor;
  740.     cvec->y /= divisor;
  741.     cvec->z /= divisor;
  742.     }
  743.  
  744.     return( divisor );
  745. }
  746.  
  747.  
  748. /*
  749.  * Set all matrix elements to zero.
  750.  */
  751. lib_zero_matrix( mx )
  752. MATRIX    mx ;
  753. {
  754.     long    i, j ;
  755.  
  756.  
  757.     for ( i = 0 ; i < 4 ; ++i ) {
  758.     for ( j = 0 ; j < 4 ; ++j ) {
  759.         mx[i][j] = 0.0 ;
  760.     }
  761.     }
  762. }
  763.  
  764.  
  765. /*
  766.  * Create identity matrix.
  767.  */
  768. lib_create_identity_matrix( mx )
  769. MATRIX    mx ;
  770. {
  771.     long    i ;
  772.  
  773.  
  774.     lib_zero_matrix( mx ) ;
  775.     for ( i = 0 ; i < 4 ; ++i ) {
  776.     mx[i][i] = 1.0 ;
  777.     }
  778. }
  779.  
  780.  
  781. /*
  782.  * Create a rotation matrix along the given axis by the given angle in radians.
  783.  */
  784. lib_create_rotate_matrix( mx, axis, angle )
  785. MATRIX    mx ;
  786. long    axis ;
  787. double    angle ;
  788. {
  789.     double  cosine ;
  790.     double  sine ;
  791.  
  792.  
  793.     lib_zero_matrix( mx ) ;
  794.  
  795.     cosine = cos( (double)angle ) ;
  796.     sine = sin( (double)angle ) ;
  797.  
  798.     switch ( axis ) {
  799.     case X_AXIS:
  800.         mx[0][0] = 1.0 ;
  801.         mx[1][1] = mx[2][2] = cosine ;
  802.         mx[1][2] = sine ;
  803.         mx[2][1] = -sine ;
  804.         break ;
  805.     case Y_AXIS:
  806.         mx[1][1] = 1.0 ;
  807.         mx[0][0] = mx[2][2] = cosine ;
  808.         mx[2][0] = sine ;
  809.         mx[0][2] = -sine ;
  810.         break ;
  811.     case Z_AXIS:
  812.         mx[2][2] = 1.0 ;
  813.         mx[0][0] = mx[1][1] = cosine ;
  814.         mx[0][1] = sine ;
  815.         mx[1][0] = -sine ;
  816.         break ;
  817.     }
  818.     mx[3][3] = 1.0 ;
  819. }
  820.  
  821.  
  822. /*
  823.  * Create a rotation matrix along the given axis by the given angle in radians.
  824.  * The axis is a set of direction cosines.
  825.  */
  826. lib_create_axis_rotate_matrix( mx, rvec, angle )
  827. MATRIX    mx ;
  828. COORD4    *rvec ;
  829. double    angle ;
  830. {
  831.     COORD4  axis ;
  832.     double  cosine ;
  833.     double  one_minus_cosine ;
  834.     double  sine ;
  835.  
  836.  
  837.     lib_zero_matrix( mx ) ;
  838.  
  839.     COPY_COORD( axis, (*rvec) ) ;
  840.  
  841.     cosine = cos( (double)angle ) ;
  842.     sine = sin( (double)angle ) ;
  843.     one_minus_cosine = 1.0 - cosine ;
  844.  
  845.     mx[0][0] = SQR(axis.x) + (1.0 - SQR(axis.x)) * cosine ;
  846.     mx[0][1] = axis.x * axis.y * one_minus_cosine + axis.z * sine ;
  847.     mx[0][2] = axis.x * axis.z * one_minus_cosine - axis.y * sine ;
  848.  
  849.     mx[1][0] = axis.x * axis.y * one_minus_cosine - axis.z * sine ;
  850.     mx[1][1] = SQR(axis.y) + (1.0 - SQR(axis.y)) * cosine ;
  851.     mx[1][2] = axis.y * axis.z * one_minus_cosine + axis.x * sine ;
  852.  
  853.     mx[2][0] = axis.x * axis.z * one_minus_cosine + axis.y * sine ;
  854.     mx[2][1] = axis.y * axis.z * one_minus_cosine - axis.x * sine ;
  855.     mx[2][2] = SQR(axis.z) + (1.0 - SQR(axis.z)) * cosine ;
  856.  
  857.     mx[3][3] = 1.0 ;
  858. }
  859.  
  860.  
  861. /*
  862.  * Multiply a 4 element vector by a matrix.
  863.  */
  864. lib_transform_coord( vres, vec, mx )
  865. COORD4    *vres ;
  866. COORD4    *vec ;
  867. MATRIX    mx ;
  868. {
  869.     vres->x =
  870.     vec->x*mx[0][0] + vec->y*mx[1][0] + vec->z*mx[2][0] + vec->w*mx[3][0] ;
  871.     vres->y =
  872.     vec->x*mx[0][1] + vec->y*mx[1][1] + vec->z*mx[2][1] + vec->w*mx[3][1] ;
  873.     vres->z =
  874.     vec->x*mx[0][2] + vec->y*mx[1][2] + vec->z*mx[2][2] + vec->w*mx[3][2] ;
  875.     vres->w =
  876.     vec->x*mx[0][3] + vec->y*mx[1][3] + vec->z*mx[2][3] + vec->w*mx[3][3] ;
  877. }
  878.  
  879.  
  880. /*
  881.  * Multiply two 4x4 matrices.
  882.  */
  883. lib_matrix_multiply( mxres, mx1, mx2 )
  884. MATRIX    mxres ;
  885. MATRIX    mx1 ;
  886. MATRIX    mx2 ;
  887. {
  888.     long    i ;
  889.     long    j ;
  890.  
  891.  
  892.     for ( i = 0; i < 4; i++ ) {
  893.     for ( j = 0; j < 4; j++ ) {
  894.         mxres[i][j] = mx1[i][0]*mx2[0][j] +
  895.               mx1[i][1]*mx2[1][j] +
  896.               mx1[i][2]*mx2[2][j] +
  897.               mx1[i][3]*mx2[3][j] ;
  898.     }
  899.     }
  900. }
  901.  
  902.  
  903. /*
  904.  * Rotate a vector pointing towards the major-axis faces (i.e. the major-axis
  905.  * component of the vector is defined as the largest value) 90 degrees to
  906.  * another cube face.  Mod_face is a face number.
  907.  *
  908.  * If the routine is called six times, with mod_face=0..5, the vector will be
  909.  * rotated to each face of a cube.  Rotations are:
  910.  *     mod_face = 0 mod 3, +Z axis rotate
  911.  *     mod_face = 1 mod 3, +X axis rotate
  912.  *     mod_face = 2 mod 3, -Y axis rotate
  913.  */
  914. lib_rotate_cube_face( vec, major_axis, mod_face )
  915. COORD4    *vec ;
  916. long    major_axis ;
  917. long    mod_face ;
  918. {
  919.     double  swap ;
  920.  
  921.  
  922.     mod_face = (mod_face+major_axis) % 3 ;
  923.     if ( mod_face == 0 ) {
  924.     swap   = vec->x ;
  925.     vec->x = -vec->y ;
  926.     vec->y = swap ;
  927.     }
  928.     else if ( mod_face == 1 ) {
  929.     swap   = vec->y ;
  930.     vec->y = -vec->z ;
  931.     vec->z = swap ;
  932.     }
  933.     else {
  934.     swap   = vec->x ;
  935.     vec->x = -vec->z ;
  936.     vec->z = swap ;
  937.     }
  938. }
  939.  
  940.  
  941. /*
  942.  * Portable gaussian random number generator (from "Numerical Recipes", GASDEV)
  943.  * Returns a uniform random deviate between 0.0 and 1.0.  'iseed' must be
  944.  * less than M1 to avoid repetition, and less than (2**31-C1)/A1 [= 300718]
  945.  * to avoid overflow.
  946.  */
  947. #define    M1    134456
  948. #define    IA1    8121
  949. #define    IC1    28411
  950. #define    RM1    1.0/M1
  951.  
  952. double    lib_gauss_rand(iseed)
  953. long    iseed ;
  954. {
  955.     double  fac ;
  956.     long    ix1, ix2 ;
  957.     double  r ;
  958.     double  v1, v2 ;
  959.  
  960.  
  961.     ix2 = iseed ;
  962.  
  963.     do {
  964.     ix1 = (IC1+ix2*IA1) % M1 ;
  965.     ix2 = (IC1+ix1*IA1) % M1 ;
  966.     v1 = ix1 * 2.0 * RM1 - 1.0 ;
  967.     v2 = ix2 * 2.0 * RM1 - 1.0 ;
  968.     r = v1*v1 + v2*v2 ;
  969.     } while ( r >= 1.0 ) ;
  970.  
  971.     fac = sqrt( (double)( -2.0 * log( (double)r ) / r ) ) ;
  972.     return( v1 * fac ) ;
  973. }
  974.  
  975.  
  976.  
  977.  
  978. /* OUTPUT ROUTINES
  979.  *
  980.  * Files are output as lines of text.  For each entity, the first line
  981.  * defines its type.  The rest of the first line and possibly other lines
  982.  * contain further information about the entity.  Entities include:
  983.  *
  984.  * "v"  - viewing vectors and angles
  985.  * "l"  - positional light location
  986.  * "b"  - background color
  987.  * "f"  - object material properties
  988.  * "c"  - cone or cylinder primitive
  989.  * "s"  - sphere primitive
  990.  * "p"  - polygon primitive
  991.  * "pp" - polygonal patch primitive
  992.  */
  993.  
  994. /*
  995.  * Output viewpoint location.  The parameters are:
  996.  *   From:  the eye location.
  997.  *   At:  a position to be at the center of the image.  A.k.a. "lookat"
  998.  *   Up:  a vector defining which direction is up.
  999.  *
  1000.  * Note that no assumptions are made about normalizing the data (e.g. the
  1001.  * from-at distance does not have to be 1).  Also, vectors are not
  1002.  * required to be perpendicular to each other.
  1003.  *
  1004.  * For all databases some viewing parameters are always the same:
  1005.  *
  1006.  *   Viewing angle is defined as from the center of top pixel row to bottom
  1007.  *     pixel row and left column to right column.
  1008.  *   Yon is "at infinity."
  1009.  *   Resolution is always 512 x 512.
  1010.  */
  1011. lib_output_viewpoint( from, at, up, angle, hither, resx, resy )
  1012. COORD4    *from ;
  1013. COORD4    *at ;
  1014. COORD4    *up ;
  1015. double    angle ;
  1016. double    hither ;
  1017. long    resx ;
  1018. long    resy ;
  1019. {
  1020.     printf( "v\n" ) ;
  1021.     printf( "from %g %g %g\n", from->x, from->y, from->z ) ;
  1022.     printf( "at %g %g %g\n", at->x, at->y, at->z ) ;
  1023.     printf( "up %g %g %g\n", up->x, up->y, up->z ) ;
  1024.     printf( "angle %g\n", angle ) ;
  1025.     printf( "hither %g\n", hither ) ;
  1026.     printf( "resolution %d %d\n", resx, resy ) ;
  1027. }
  1028.  
  1029.  
  1030. /*
  1031.  * Output light.  A light is defined by position.  All lights have the same
  1032.  * intensity.
  1033.  *
  1034.  */
  1035. lib_output_light( center_pt )
  1036. COORD4    *center_pt ;
  1037. {
  1038.     printf( "l %g %g %g\n", center_pt->x, center_pt->y, center_pt->z ) ;
  1039. }
  1040.  
  1041.  
  1042. /*
  1043.  * Output background color.  A color is simply RGB (monitor dependent, but
  1044.  * that's life).  The format is:
  1045.  *     "b" red green blue
  1046.  */
  1047. lib_output_background_color( color )
  1048. COORD4    *color ;
  1049. {
  1050.     printf( "b %g %g %g\n", color->x, color->y, color->z ) ;
  1051. }
  1052.  
  1053.  
  1054. /*
  1055.  * Output a color and shading parameters for the object in the format:
  1056.  *     "f" red green blue Kd Ks Shine T index_of_refraction
  1057.  *
  1058.  * Kd is the diffuse component, Ks the specular, Shine is the Phong cosine
  1059.  * power for highlights, T is transmittance (fraction of light passed per
  1060.  * unit).  0 <= Kd <= 1 and 0 <= Ks <= 1, though it is not required that
  1061.  * Kd + Ks == 1.
  1062.  *
  1063.  * The fill color is used to color the objects following it until a new color
  1064.  * is assigned or the file ends.
  1065.  */
  1066. lib_output_color( color, kd, ks, shine, t, i_of_r )
  1067. COORD4    *color ;
  1068. double    kd ;
  1069. double    ks ;
  1070. double    shine ;
  1071. double    t ;
  1072. double    i_of_r ;
  1073. {
  1074.     printf( "f %g %g %g %g %g %g %g %g\n", color->x, color->y, color->z,
  1075.                         kd, ks, shine, t, i_of_r ) ;
  1076. }
  1077.  
  1078.  
  1079. /*
  1080.  * Output cylinder or cone.  A cylinder is defined as having a radius and an
  1081.  * axis defined by two points, which also define the top and bottom edge of the
  1082.  * cylinder.  A cone is defined similarly, the difference being that the apex
  1083.  * and base radii are different.  The apex radius is defined as being smaller
  1084.  * than the base radius.  Note that the surface exists without endcaps.
  1085.  *
  1086.  * If format=OUTPUT_CURVES, output the cylinder/cone in format:
  1087.  *     "c"
  1088.  *     base.x base.y base.z base_radius
  1089.  *     apex.x apex.y apex.z apex_radius
  1090.  *
  1091.  * If the format=OUTPUT_POLYGONS, the surface is polygonalized and output.
  1092.  * (4*OUTPUT_RESOLUTION) polygons are output as rectangles by
  1093.  * lib_output_polypatch.
  1094.  */
  1095. lib_output_cylcone( base_pt, apex_pt, format )
  1096. COORD4    *base_pt ;
  1097. COORD4    *apex_pt ;
  1098. long    format ;
  1099. {
  1100.     double  angle ;
  1101.     COORD4  axis ;
  1102.     COORD4  dir ;
  1103.     double  divisor ;
  1104.     COORD4  lip_norm[4], lip_pt[4] ;
  1105.     MATRIX  mx ;
  1106.     COORD4  norm_axis ;
  1107.     long    num_pol ;
  1108.     COORD4  start_norm, start_radius[4] ;
  1109.  
  1110.  
  1111.     if ( format == OUTPUT_CURVES ) {
  1112.     printf( "c\n" ) ;
  1113.     printf( "%g %g %g %g\n",
  1114.                 base_pt->x, base_pt->y, base_pt->z, base_pt->w ) ;
  1115.     printf( "%g %g %g %g\n",
  1116.                 apex_pt->x, apex_pt->y, apex_pt->z, apex_pt->w ) ;
  1117.     }
  1118.     else {
  1119.     SUB3_COORD( axis, (*apex_pt), (*base_pt) ) ;
  1120.     COPY_COORD( norm_axis, axis ) ;
  1121.     lib_normalize_coord3( &norm_axis ) ;
  1122.  
  1123.     dir.x = 0.0 ; dir.y = 0.0 ; dir.z = 1.0 ; dir.w = 0.0 ;
  1124.     CROSS( start_norm, axis, dir ) ;
  1125.  
  1126.     divisor = lib_normalize_coord3( &start_norm ) ;
  1127.     if ( ABSOLUTE( divisor ) < EPSILON ) {
  1128.         dir.x = 1.0 ; dir.y = 0.0 ; dir.z = 0.0 ;
  1129.         CROSS( start_norm, axis, dir ) ;
  1130.         lib_normalize_coord3( &start_norm ) ;
  1131.     }
  1132.  
  1133.     start_radius[0].x = start_norm.x * base_pt->w ;
  1134.     start_radius[0].y = start_norm.y * base_pt->w ;
  1135.     start_radius[0].z = start_norm.z * base_pt->w ;
  1136.     start_radius[0].w = 0.0 ;
  1137.     ADD3_COORD( lip_pt[0], (*base_pt), start_radius[0] ) ;
  1138.  
  1139.     start_radius[1].x = start_norm.x * apex_pt->w ;
  1140.     start_radius[1].y = start_norm.y * apex_pt->w ;
  1141.     start_radius[1].z = start_norm.z * apex_pt->w ;
  1142.     start_radius[1].w = 0.0 ;
  1143.     ADD3_COORD( lip_pt[1], (*apex_pt), start_radius[1] ) ;
  1144.  
  1145.     COPY_COORD4( lip_norm[0], start_norm ) ;
  1146.     COPY_COORD4( lip_norm[1], start_norm ) ;
  1147.  
  1148.     for ( num_pol = 0 ; num_pol < 4*OUTPUT_RESOLUTION ; ++num_pol ) {
  1149.         COPY_COORD4( lip_pt[3], lip_pt[0] ) ;
  1150.         COPY_COORD4( lip_pt[2], lip_pt[1] ) ;
  1151.         COPY_COORD4( lip_norm[3], lip_norm[0] ) ;
  1152.         COPY_COORD4( lip_norm[2], lip_norm[1] ) ;
  1153.  
  1154.         angle = 2.0 * PI *
  1155.         (double)( num_pol+1 ) / (double)( 4*OUTPUT_RESOLUTION ) ;
  1156.         lib_create_axis_rotate_matrix( mx, &norm_axis, angle ) ;
  1157.  
  1158.         lib_transform_coord( &lip_pt[0], &start_radius[0], mx ) ;
  1159.         ADD2_COORD( lip_pt[0], (*base_pt) ) ;
  1160.         lib_transform_coord( &lip_pt[1], &start_radius[1], mx ) ;
  1161.         ADD2_COORD( lip_pt[1], (*apex_pt) ) ;
  1162.  
  1163.         lib_transform_coord( &lip_norm[0], &start_norm, mx ) ;
  1164.         COPY_COORD4( lip_norm[1], lip_norm[0] ) ;
  1165.  
  1166.         lib_output_polypatch( 4, lip_pt, lip_norm ) ;
  1167.     }
  1168.     }
  1169. }
  1170.  
  1171.  
  1172. /*
  1173.  * Output sphere.  A sphere is defined by a radius and center position.
  1174.  *
  1175.  * If format=OUTPUT_CURVES, output the sphere in format:
  1176.  *     "s" center.x center.y center.z radius
  1177.  *
  1178.  * If the format=OUTPUT_POLYGONS, the sphere is polygonalized and output.
  1179.  * The sphere is polygonalized by splitting it into 6 faces (of a cube
  1180.  * projected onto the sphere) and dividing these faces by equally spaced
  1181.  * great circles.  OUTPUT_RESOLUTION affects the number of great circles.
  1182.  * (6*2*OUTPUT_RESOLUTION*OUTPUT_RESOLUTION) polygons are output as triangles
  1183.  * using lib_output_polypatch.
  1184.  */
  1185. lib_output_sphere( center_pt, format )
  1186. COORD4    *center_pt ;
  1187. long    format ;
  1188. {
  1189.     double  angle ;
  1190.     COORD4  edge_norm[3], edge_pt[3] ;
  1191.     long    num_face, num_edge, num_tri, num_vert ;
  1192.     COORD4  x_axis[OUTPUT_RESOLUTION+1], y_axis[OUTPUT_RESOLUTION+1] ;
  1193.     COORD4  pt[OUTPUT_RESOLUTION+1][OUTPUT_RESOLUTION+1] ;
  1194.     COORD4  mid_axis ;
  1195.     MATRIX  rot_mx ;
  1196.     long    u_pol, v_pol ;
  1197.  
  1198.  
  1199.     if ( format == OUTPUT_CURVES ) {
  1200.     printf( "s %g %g %g %g\n",
  1201.             center_pt->x, center_pt->y, center_pt->z, center_pt->w ) ;
  1202.     }
  1203.     else {
  1204.     /* calculate axes used to find grid points */
  1205.     for ( num_edge = 0 ; num_edge <= OUTPUT_RESOLUTION ; ++num_edge ) {
  1206.          angle = (PI/4.0) * (2.0*(double)num_edge/OUTPUT_RESOLUTION - 1.0) ;
  1207.         mid_axis.w = 0.0 ;
  1208.  
  1209.         mid_axis.x = 1.0 ; mid_axis.y = 0.0 ; mid_axis.z = 0.0 ;
  1210.         lib_create_rotate_matrix( rot_mx, Y_AXIS, angle ) ;
  1211.         lib_transform_coord( &x_axis[num_edge], &mid_axis, rot_mx ) ;
  1212.  
  1213.         mid_axis.x = 0.0 ; mid_axis.y = 1.0 ; mid_axis.z = 0.0 ;
  1214.         lib_create_rotate_matrix( rot_mx, X_AXIS, angle ) ;
  1215.         lib_transform_coord( &y_axis[num_edge], &mid_axis, rot_mx ) ;
  1216.     }
  1217.  
  1218.     /* set up grid of points on +Z sphere surface */
  1219.     for ( u_pol = 0 ; u_pol <= OUTPUT_RESOLUTION ; ++u_pol ) {
  1220.         for ( v_pol = 0 ; v_pol <= OUTPUT_RESOLUTION ; ++v_pol ) {
  1221.         CROSS( pt[u_pol][v_pol], x_axis[u_pol], y_axis[v_pol] ) ;
  1222.         lib_normalize_coord3( &pt[u_pol][v_pol] ) ;
  1223.         pt[u_pol][v_pol].w = 1.0 ;
  1224.         }
  1225.     }
  1226.     for ( num_face = 0 ; num_face < 6 ; ++num_face ) {
  1227.         /* transform points to cube face */
  1228.         for ( u_pol = 0 ; u_pol <= OUTPUT_RESOLUTION ; ++u_pol ) {
  1229.         for ( v_pol = 0 ; v_pol <= OUTPUT_RESOLUTION ; ++v_pol ) {
  1230.             lib_rotate_cube_face( &pt[u_pol][v_pol]
  1231.                     , Z_AXIS
  1232.                     , num_face
  1233.                     ) ;
  1234.         }
  1235.         }
  1236.         /* output grid */
  1237.         for ( u_pol = 0 ; u_pol < OUTPUT_RESOLUTION ; ++u_pol ) {
  1238.         for ( v_pol = 0 ; v_pol < OUTPUT_RESOLUTION ; ++v_pol ) {
  1239.             for ( num_tri = 0 ; num_tri < 2 ; ++num_tri ) {
  1240.             for ( num_edge = 0 ; num_edge < 3 ; ++num_edge ) {
  1241.                 num_vert = (num_tri*2 + num_edge) % 4 ;
  1242.                 if ( num_vert == 0 ) {
  1243.                 COPY_COORD4( edge_pt[num_edge],
  1244.                          pt[u_pol][v_pol] ) ;
  1245.                 }
  1246.                 else if ( num_vert == 1 ) {
  1247.                 COPY_COORD4( edge_pt[num_edge],
  1248.                          pt[u_pol][v_pol+1] ) ;
  1249.                 }
  1250.                 else if ( num_vert == 2 ) {
  1251.                 COPY_COORD4( edge_pt[num_edge],
  1252.                          pt[u_pol+1][v_pol+1] ) ;
  1253.                 }
  1254.                 else {
  1255.                 COPY_COORD4( edge_pt[num_edge],
  1256.                          pt[u_pol+1][v_pol] ) ;
  1257.                 }
  1258.                 COPY_COORD4( edge_norm[num_edge],
  1259.                      edge_pt[num_edge] ) ;
  1260.                 edge_pt[num_edge].x =
  1261.                     edge_pt[num_edge].x * center_pt->w +
  1262.                                   center_pt->x ;
  1263.                 edge_pt[num_edge].y =
  1264.                     edge_pt[num_edge].y * center_pt->w +
  1265.                                   center_pt->y ;
  1266.                 edge_pt[num_edge].z =
  1267.                     edge_pt[num_edge].z * center_pt->w +
  1268.                                   center_pt->z ;
  1269.  
  1270.             }
  1271.             lib_output_polypatch( 3, edge_pt, edge_norm ) ;
  1272.             }
  1273.         }
  1274.         }
  1275.     }
  1276.     }
  1277. }
  1278.  
  1279.  
  1280. /*
  1281.  * Output polygon.  A polygon is defined by a set of vertices.  With these
  1282.  * databases, a polygon is defined to have all points coplanar.  A polygon has
  1283.  * only one side, with the order of the vertices being counterclockwise as you
  1284.  * face the polygon (right-handed coordinate system).
  1285.  *
  1286.  * The output format is always:
  1287.  *     "p" total_vertices
  1288.  *     vert1.x vert1.y vert1.z
  1289.  *     [etc. for total_vertices polygons]
  1290.  *
  1291.  */
  1292. lib_output_polygon( tot_vert, vert )
  1293. long    tot_vert ;
  1294. COORD4    *vert ;
  1295. {
  1296.     long    num_vert ;
  1297.  
  1298.  
  1299.     printf( "p %d\n", tot_vert ) ;
  1300.  
  1301.     for ( num_vert = 0 ; num_vert < tot_vert ; ++num_vert ) {
  1302.     printf( "%g %g %g\n", vert[num_vert].x
  1303.                 , vert[num_vert].y
  1304.                 , vert[num_vert].z
  1305.                 ) ;
  1306.     }
  1307. }
  1308.  
  1309.  
  1310. /*
  1311.  * Output polygonal patch.  A patch is defined by a set of vertices and their
  1312.  * normals.  With these databases, a patch is defined to have all points
  1313.  * coplanar.  A patch has only one side, with the order of the vertices being
  1314.  * counterclockwise as you face the patch (right-handed coordinate system).
  1315.  *
  1316.  * The output format is always:
  1317.  *     "pp" total_vertices
  1318.  *     vert1.x vert1.y vert1.z norm1.x norm1.y norm1.z
  1319.  *     [etc. for total_vertices polygonal patches]
  1320.  *
  1321.  */
  1322. lib_output_polypatch( tot_vert, vert, norm )
  1323. long    tot_vert ;
  1324. COORD4    *vert ;
  1325. COORD4    *norm ;
  1326. {
  1327.     long    num_vert ;
  1328.  
  1329.  
  1330.     printf( "pp %d\n", tot_vert ) ;
  1331.  
  1332.     for ( num_vert = 0 ; num_vert < tot_vert ; ++num_vert ) {
  1333.     printf( "%g %g %g %g %g %g\n", vert[num_vert].x
  1334.                      , vert[num_vert].y
  1335.                      , vert[num_vert].z
  1336.                      , norm[num_vert].x
  1337.                      , norm[num_vert].y
  1338.                      , norm[num_vert].z
  1339.                      ) ;
  1340.     }
  1341. }
  1342. @//E*O*F lib.c//
  1343. chmod u=rw,g=r,o= lib.c
  1344. echo x - balls.c
  1345. sed 's/^@//' > "balls.c" <<'@//E*O*F balls.c//'
  1346. /*
  1347.  * balls.c - Create a set of shiny spheres, with each sphere blooming sets of
  1348.  *     9 more spheres with 1/3rd radius.  None of the spheres are clipped.  A
  1349.  *     square floor polygon is added.  Three light sources.
  1350.  *
  1351.  * Version:  2.2 (11/17/87)
  1352.  * Author:  Eric Haines, 3D/Eye, Inc.
  1353.  *
  1354.  * SIZE_FACTOR determines the number of objects output.
  1355.  *     Total spheres = sum of n=0,SF of (9**SF).
  1356.  *
  1357.  *     SIZE_FACTOR    # spheres    # squares
  1358.  *        1            10             1
  1359.  *        2            91             1
  1360.  *        3           820             1
  1361.  *
  1362.  *        4          7381             1
  1363.  */
  1364.  
  1365. #include <stdio.h>
  1366. #include <math.h>
  1367. #include <memory.h>
  1368. #include "def.h"
  1369. #include "lib.h"
  1370.  
  1371. #define    OUTPUT_FORMAT        OUTPUT_CURVES
  1372. #define    SIZE_FACTOR        4
  1373.  
  1374. static    COORD4    objset[9] ;
  1375.  
  1376.  
  1377. main(argc,argv)
  1378. int argc ;
  1379. char *argv[] ;
  1380. {
  1381.     COORD4  back_color, obj_color ;
  1382.     COORD4  backg[4], bvec, light ;
  1383.     COORD4  from, at, up ;
  1384.     COORD4  center_pt, direction ;
  1385.     double  radius ;
  1386.  
  1387.  
  1388.     /* set radius of sphere which would enclose entire object */
  1389.     radius = 1.0 ;
  1390.  
  1391.     /* output viewpoint */
  1392.     SET_COORD( from, 2.1, 1.3, 1.7 ) ;
  1393.     SET_COORD( at, 0.0, 0.0, 0.0 ) ;
  1394.     SET_COORD( up, 0.0, 0.0, 1.0 ) ;
  1395.     lib_output_viewpoint( &from, &at, &up, 45.0, 1.0, 512, 512 ) ;
  1396.  
  1397.     /* output background color - UNC sky blue */
  1398.     SET_COORD( back_color, 0.078, 0.361, 0.753 ) ;
  1399.     lib_output_background_color( &back_color ) ;
  1400.  
  1401.     /* output light sources */
  1402.     SET_COORD( light, 4.0, 3.0, 2.0 ) ;
  1403.     lib_output_light( &light ) ;
  1404.     SET_COORD( light, 1.0, -4.0, 4.0 ) ;
  1405.     lib_output_light( &light ) ;
  1406.     SET_COORD( light, -3.0, 1.0, 5.0 ) ;
  1407.     lib_output_light( &light ) ;
  1408.  
  1409.     /* output floor polygon - beige */
  1410.     SET_COORD( back_color, 1.0, 0.75, 0.33 ) ;
  1411.     lib_output_color( &back_color, 1.0, 0.0, 0.0, 0.0, 0.0 ) ;
  1412.     bvec.x = bvec.y = radius * 12.0 ;
  1413.     bvec.z = -radius / 2.0 ;
  1414.     SET_COORD( backg[0],  bvec.x,  bvec.y, bvec.z ) ;
  1415.     SET_COORD( backg[1], -bvec.x,  bvec.y, bvec.z ) ;
  1416.     SET_COORD( backg[2], -bvec.x, -bvec.y, bvec.z ) ;
  1417.     SET_COORD( backg[3],  bvec.x, -bvec.y, bvec.z ) ;
  1418.     lib_output_polygon( 4, backg ) ;
  1419.  
  1420.     /* set up object color - off white */
  1421.     SET_COORD( obj_color, 1.0, 0.9, 0.7 ) ;
  1422.     lib_output_color( &obj_color, 0.5, 0.5, 3.0, 0.0, 0.0 ) ;
  1423.  
  1424.     /* create set of spawned points */
  1425.     create_objset() ;
  1426.  
  1427.     /* compute and output object */
  1428.     SET_COORD4( center_pt, 0.0, 0.0, 0.0, radius / 2.0 ) ;
  1429.     SET_COORD4( direction, 0.0, 0.0, 1.0, 1.0/3.0 ) ;
  1430.     output_object( SIZE_FACTOR, ¢er_pt, &direction ) ;
  1431. }
  1432.  
  1433.  
  1434. /* Create the set of 9 vectors needed to generate the sphere set. */
  1435. /* Uses global 'objset' */
  1436. create_objset()
  1437. {
  1438.     COORD4  axis, temp_pt, trio_dir[3] ;
  1439.     double  dist ;
  1440.     MATRIX  mx ;
  1441.     long    num_set, num_vert ;
  1442.  
  1443.  
  1444.     dist = 1.0 / sqrt( (double)2.0 ) ;
  1445.  
  1446.     SET_COORD4( trio_dir[0], dist, dist,   0.0, 0.0 ) ;
  1447.     SET_COORD4( trio_dir[1], dist,  0.0, -dist, 0.0 ) ;
  1448.     SET_COORD4( trio_dir[2],  0.0, dist, -dist, 0.0 ) ;
  1449.  
  1450.     SET_COORD( axis, 1.0, -1.0, 0.0 ) ;
  1451.     lib_normalize_coord3( &axis ) ;
  1452.     lib_create_axis_rotate_matrix(
  1453.       mx,
  1454.       &axis,
  1455.       asin( (double) ( 2.0 / sqrt( (double)6.0 ) ) ) ) ;
  1456.  
  1457.     for ( num_vert = 0 ; num_vert < 3 ; ++num_vert ) {
  1458.     lib_transform_coord( &temp_pt, &trio_dir[num_vert], mx ) ;
  1459.     COPY_COORD( trio_dir[num_vert], temp_pt ) ;
  1460.     }
  1461.  
  1462.     for ( num_set = 0 ; num_set < 3 ; ++num_set ) {
  1463.     lib_create_rotate_matrix( mx, Z_AXIS, num_set*2.0*PI/3.0 ) ;
  1464.     for ( num_vert = 0 ; num_vert < 3 ; ++num_vert ) {
  1465.         lib_transform_coord( &objset[num_set*3+num_vert],
  1466.                             &trio_dir[num_vert], mx ) ;
  1467.     }
  1468.     }
  1469. }
  1470.  
  1471.  
  1472. /*
  1473.  * Output the parent sphere, then output the children of the sphere.
  1474.  * Uses global 'objset'.
  1475.  */
  1476. output_object( depth, center, direction )
  1477. long    depth ;
  1478. COORD4    *center ;
  1479. COORD4    *direction ;
  1480. {
  1481.     double  angle ;
  1482.     COORD4  axis, z_axis ;
  1483.     COORD4  child_pt, child_dir ;
  1484.     MATRIX  mx ;
  1485.     long    num_vert ;
  1486.     double  scale ;
  1487.  
  1488.  
  1489.     /* output sphere at location & radius defined by center */
  1490.     lib_output_sphere( center, OUTPUT_FORMAT ) ;
  1491.  
  1492.     /* check if children should be generated */
  1493.     if ( depth > 0 ) {
  1494.     --depth ;
  1495.  
  1496.     /* rotation matrix to new axis from +Z axis */
  1497.     if ( direction->z >= 1.0 ) {
  1498.         /* identity matrix */
  1499.         lib_create_identity_matrix( mx ) ;
  1500.     }
  1501.     else if ( direction->z <= -1.0 ) {
  1502.         lib_create_rotate_matrix( mx, Y_AXIS, PI ) ;
  1503.     }
  1504.     else {
  1505.         SET_COORD( z_axis, 0.0, 0.0, 1.0 ) ;
  1506.         CROSS( axis, z_axis, (*direction) ) ;
  1507.         lib_normalize_coord3( &axis ) ;
  1508.         angle = acos( (double)DOT_PRODUCT( z_axis, (*direction) ) ) ;
  1509.         lib_create_axis_rotate_matrix( mx, &axis, angle ) ;
  1510.     }
  1511.  
  1512.     /* scale down location of new spheres */
  1513.     scale = center->w * (1.0 + direction->w ) ;
  1514.  
  1515.     for ( num_vert = 0 ; num_vert < 9 ; ++num_vert ) {
  1516.         lib_transform_coord( &child_pt, &objset[num_vert], mx ) ;
  1517.         child_pt.x = child_pt.x * scale + center->x ;
  1518.         child_pt.y = child_pt.y * scale + center->y ;
  1519.         child_pt.z = child_pt.z * scale + center->z ;
  1520.         /* scale down radius */
  1521.         child_pt.w = center->w * direction->w ;
  1522.         SUB3_COORD( child_dir, child_pt, (*center) ) ;
  1523.         child_dir.x /= scale ;
  1524.         child_dir.y /= scale ;
  1525.         child_dir.z /= scale ;
  1526.         child_dir.w = direction->w ;
  1527.         output_object( depth, &child_pt, &child_dir ) ;
  1528.     }
  1529.     }
  1530. }
  1531. @//E*O*F balls.c//
  1532. chmod u=rw,g=r,o= balls.c
  1533. echo x - gears.c
  1534. sed 's/^@//' > "gears.c" <<'@//E*O*F gears.c//'
  1535. /*
  1536.  * gears.c - Create a set of gears.  Each gear face has 144 vertices, and
  1537.  *    contains concavities.  Note that the first 3 vertices of all polygons
  1538.  *    define the two edges of a convex section of the polygon.  Background
  1539.  *    square floor is reflective.  Some gears are clipped.
  1540.  *    Five light sources.
  1541.  *
  1542.  * Version:  2.2 (11/17/87)
  1543.  * Author:  Eric Haines, 3D/Eye, Inc.
  1544.  *
  1545.  * SIZE_FACTOR determines the number of polygons output.
  1546.  *     Total gears = SF**3:  concave polygons = 2 * SF**3
  1547.  *     rectangles = 4*TEETH * SF**3
  1548.  *
  1549.  *     SIZE_FACTOR    # gears       # gear faces    # rectangles
  1550.  *        1            1          2        144
  1551.  *        2            8         16           1152
  1552.  *        3           27         54           3888
  1553.  *        4           64        128           9216
  1554.  */
  1555.  
  1556. #include <stdio.h>
  1557. #include <math.h>
  1558. #include <memory.h>
  1559. #include "def.h"
  1560. #include "lib.h"
  1561.  
  1562. #define    SIZE_FACTOR        4
  1563.  
  1564. /* define number of teeth on a gear - must be a multiple of 4 */
  1565. #define    TEETH            36
  1566. /* define ratio of radius taken up by teeth and the gear thickness */
  1567. #define    EDGE_RATIO        0.1
  1568. #define    DEPTH_RATIO        0.1
  1569.  
  1570.  
  1571. main(argc,argv)
  1572. int argc ;
  1573. char *argv[] ;
  1574. {
  1575.     COORD4  back_color, gear_color ;
  1576.     COORD4  center_pt, floor[4], light, offset, zero_pt ;
  1577.     COORD4  from, at, up ;
  1578.     double  angle, color_scale, outer_radius, thickness ;
  1579.     long    ix, iy, iz ;
  1580.  
  1581.  
  1582.     /* output viewpoint */
  1583.     SET_COORD( from, -1.1, -2.1, 2.6 ) ;
  1584.     SET_COORD( at, 0.0, 0.0, 0.0 ) ;
  1585.     SET_COORD( up, 0.0, 0.0, 1.0 ) ;
  1586.     lib_output_viewpoint( &from, &at, &up, 45.0, 1.0, 512, 512 ) ;
  1587.  
  1588.     /* output background color - UNC sky blue */
  1589.     SET_COORD( back_color, 0.078, 0.361, 0.753 ) ;
  1590.     lib_output_background_color( &back_color ) ;
  1591.  
  1592.     /* output light sources */
  1593.     SET_COORD( light, 2.0, 4.0, 4.0 ) ;
  1594.     lib_output_light( &light ) ;
  1595.     SET_COORD( light, -2.0, 4.0, 3.0 ) ;
  1596.     lib_output_light( &light ) ;
  1597.     SET_COORD( light, 2.0, -2.5, 2.5 ) ;
  1598.     lib_output_light( &light ) ;
  1599.     SET_COORD( light, -1.0, -4.0, 2.0 ) ;
  1600.     lib_output_light( &light ) ;
  1601.     /* just behind the eye */
  1602.     SET_COORD( light, -1.111, -2.121, 2.626 ) ;
  1603.     lib_output_light( &light ) ;
  1604.  
  1605.     /* output floor polygon - off white */
  1606.     SET_COORD( back_color, 1.0, 0.85, 0.7 ) ;
  1607.     lib_output_color( &back_color, 0.75, 0.25, 25.0, 0.0, 0.0 ) ;
  1608.     SET_COORD( floor[0], 2.0, 2.0, 0.0 ) ;
  1609.     SET_COORD( floor[1], -2.0, 2.0, 0.0 ) ;
  1610.     SET_COORD( floor[2], -2.0, -2.0, 0.0 ) ;
  1611.     SET_COORD( floor[3], 2.0, -2.0, 0.0 ) ;
  1612.     lib_output_polygon( 4, floor ) ;
  1613.  
  1614.     outer_radius = 1.0 /
  1615.     ( (double)SIZE_FACTOR - (double)(SIZE_FACTOR-1) * EDGE_RATIO / 2.0 ) ;
  1616.     /* calculate first gear center */
  1617.     zero_pt.x = zero_pt.y = -1.0 + outer_radius ;
  1618.     zero_pt.z = 1.0 ;
  1619.     /* calculate offset */
  1620.     offset.x = offset.y = outer_radius * ( 2.0 - EDGE_RATIO ) ;
  1621.     offset.z = -1.0 / (double)SIZE_FACTOR ;
  1622.  
  1623.     /* create gears */
  1624.     for ( iz = 0 ; iz < SIZE_FACTOR ; ++iz ) {
  1625.     center_pt.z = zero_pt.z + (double)iz * offset.z ;
  1626.     for ( iy = 0 ; iy < SIZE_FACTOR ; ++iy ) {
  1627.         center_pt.y = zero_pt.y + (double)iy * offset.y ;
  1628.         for ( ix = 0 ; ix < SIZE_FACTOR ; ++ix ) {
  1629.         center_pt.x = zero_pt.x + (double)ix * offset.x ;
  1630.  
  1631.         /* output pseudo-random gear color */
  1632.         SET_COORD( gear_color
  1633.              , 0.01 + FRACTION( (double)(ix*3+iy*2+iz+1)*5.0/7.0 )
  1634.              , 0.01 + FRACTION( (double)(iy*3+iz*2+ix+1)*3.0/7.0 )
  1635.              , 0.01 + FRACTION( (double)(iz*3+ix*2+iy+1)*2.0/7.0 )
  1636.              ) ;
  1637.         color_scale = MAX3( gear_color.x, gear_color.y, gear_color.z );
  1638.         gear_color.x /= color_scale ;
  1639.         gear_color.y /= color_scale ;
  1640.         gear_color.z /= color_scale ;
  1641.         if ( ( ix*4 + iy*2 + iz ) % 5 == 0 ) {
  1642.             lib_output_color( &gear_color,
  1643.                         0.75, 0.25, 50.0, 0.95, 1.1 ) ;
  1644.         }
  1645.         else {
  1646.             lib_output_color( &gear_color,
  1647.                         1.0, 0.0, 0.0, 0.0, 0.0 ) ;
  1648.         }
  1649.  
  1650.         /* output gear */
  1651.         angle = PI * (double)( (ix+iy+iz) % 2 ) / (double)(TEETH) ;
  1652.         thickness =
  1653.             MIN( DEPTH_RATIO, 1.0 / ( 2.0 * (double)SIZE_FACTOR ) ) ;
  1654.         create_gear( ¢er_pt,
  1655.                  angle,
  1656.                  outer_radius,
  1657.                  (1.0 - EDGE_RATIO) * outer_radius,
  1658.                  thickness ) ;
  1659.         }
  1660.     }
  1661.     }
  1662. }
  1663.  
  1664.  
  1665. /* Create gear */
  1666. create_gear( center, offset_angle, outer_radius, inner_radius, thickness )
  1667. COORD4    *center ;
  1668. double    offset_angle ;
  1669. double    outer_radius ;
  1670. double    inner_radius ;
  1671. double    thickness ;
  1672. {
  1673.     COORD4    side_pts[4], gear_pts[4*TEETH], outer_pt, inner_pt ;
  1674.     long    next_side, num_side, num_teeth ;
  1675.     double    gear_angle, tooth_angle ;
  1676.  
  1677.  
  1678.     outer_pt.x = outer_radius ;
  1679.     outer_pt.y = 0.0 ;
  1680.     outer_pt.z = 0.0 ;
  1681.     outer_pt.w = 1.0 ;
  1682.     inner_pt.x = inner_radius ;
  1683.     inner_pt.y = 0.0 ;
  1684.     inner_pt.z = 0.0 ;
  1685.     inner_pt.w = 1.0 ;
  1686.  
  1687.     tooth_angle = 2.0 * PI / (double)TEETH ;
  1688.  
  1689.     /* output gear top */
  1690.     for ( num_teeth = 0 ; num_teeth < TEETH ; ++num_teeth ) {
  1691.     gear_angle = offset_angle +
  1692.         2.0 * PI * (double)num_teeth / (double)TEETH ;
  1693.     create_tooth( gear_angle
  1694.             , tooth_angle
  1695.             , center
  1696.             , &outer_pt
  1697.             , &inner_pt
  1698.             , &gear_pts[num_teeth*4]
  1699.             ) ;
  1700.     }
  1701.     lib_output_polygon( 4*TEETH, gear_pts ) ;
  1702.  
  1703.     /* output teeth */
  1704.     for ( num_side = 0 ; num_side < 4 * TEETH ; ++num_side ) {
  1705.     next_side = ( num_side + 1 ) % ( 4 * TEETH ) ;
  1706.     COPY_COORD( side_pts[0], gear_pts[num_side] ) ;
  1707.     COPY_COORD( side_pts[1], gear_pts[num_side] ) ;
  1708.     side_pts[1].z -= thickness ;
  1709.     COPY_COORD( side_pts[2], gear_pts[next_side] ) ;
  1710.     side_pts[2].z -= thickness ;
  1711.     COPY_COORD( side_pts[3], gear_pts[next_side] ) ;
  1712.     lib_output_polygon( 4, side_pts ) ;
  1713.     }
  1714.  
  1715.     /* output gear bottom */
  1716.     outer_pt.z = inner_pt.z = -thickness ;
  1717.     for ( num_teeth = 0 ; num_teeth < TEETH ; ++num_teeth ) {
  1718.     gear_angle = offset_angle -
  1719.         2.0 * PI * (double)num_teeth / (double)TEETH ;
  1720.     create_tooth( gear_angle
  1721.             , -tooth_angle
  1722.             , center
  1723.             , &outer_pt
  1724.             , &inner_pt
  1725.             , &gear_pts[num_teeth*4]
  1726.             ) ;
  1727.     }
  1728.     lib_output_polygon( 4*TEETH, gear_pts ) ;
  1729. }
  1730.  
  1731.  
  1732. /* Create gear tooth */
  1733. create_tooth( gear_angle, tooth_angle, center, outer_pt, inner_pt, edge_pts )
  1734. double    gear_angle ;
  1735. double    tooth_angle ;
  1736. COORD4    *center ;
  1737. COORD4    *outer_pt ;
  1738. COORD4    *inner_pt ;
  1739. COORD4    *edge_pts ;
  1740. {
  1741.     MATRIX    mx ;
  1742.  
  1743.  
  1744.     lib_create_rotate_matrix( mx
  1745.                 , Z_AXIS
  1746.                 , gear_angle - 0.19 * tooth_angle ) ;
  1747.     lib_transform_coord( &edge_pts[0], outer_pt, mx ) ;
  1748.     ADD2_COORD( edge_pts[0], *center ) ;
  1749.     lib_create_rotate_matrix( mx
  1750.                 , Z_AXIS
  1751.                 , gear_angle + 0.19 * tooth_angle ) ;
  1752.     lib_transform_coord( &edge_pts[1], outer_pt, mx ) ;
  1753.     ADD2_COORD( edge_pts[1], *center ) ;
  1754.     lib_create_rotate_matrix( mx
  1755.                 , Z_AXIS
  1756.                 , gear_angle + 0.3 * tooth_angle ) ;
  1757.     lib_transform_coord( &edge_pts[2], inner_pt, mx ) ;
  1758.     ADD2_COORD( edge_pts[2], *center ) ;
  1759.     lib_create_rotate_matrix( mx
  1760.                 , Z_AXIS
  1761.                 , gear_angle + 0.7 * tooth_angle ) ;
  1762.     lib_transform_coord( &edge_pts[3], inner_pt, mx ) ;
  1763.     ADD2_COORD( edge_pts[3], *center ) ;
  1764. }
  1765. @//E*O*F gears.c//
  1766. chmod u=rw,g=r,o= gears.c
  1767. echo x - mountain.c
  1768. sed 's/^@//' > "mountain.c" <<'@//E*O*F mountain.c//'
  1769. /*
  1770.  * mountain.c - creates a fractal mountain, using Carpenter's method with a
  1771.  *     different extension to square grids.  A pyramid of 4 glass spheres
  1772.  *     is added in front of the mountain.  None of the spheres are clipped.
  1773.  *     A few of the polygons are clipped.  One light source.
  1774.  *
  1775.  * Version:  2.2 (11/17/87)
  1776.  * Author:  Eric Haines, 3D/Eye, Inc.
  1777.  *
  1778.  * SIZE_FACTOR determines the number of objects output.
  1779.  *     Total triangular polygons = 2 * (4**SIZE_FACTOR)
  1780.  *
  1781.  *     SIZE_FACTOR    # triangles    # spheres
  1782.  *        1             8             4
  1783.  *        2            32             4
  1784.  *        3           128             4
  1785.  *
  1786.  *        6          8192             4
  1787.  */
  1788.  
  1789. #include <stdio.h>
  1790. #include <math.h>
  1791. #include <memory.h>
  1792. #include "def.h"
  1793. #include "lib.h"
  1794.  
  1795. #define    OUTPUT_FORMAT        OUTPUT_CURVES
  1796. /* size factor determines number of polygons */
  1797. #define    SIZE_FACTOR        6
  1798.  
  1799. /* fractal dimension - affects variance of z.  Between 2 and 3 */
  1800. #define    FRACTAL_DIMENSION    2.2
  1801. /* change MOUNTAIN_NO to get a different mountain */
  1802. #define    MOUNTAIN_NO        21
  1803.  
  1804. /* lower left corner and width of mountain definitions */
  1805. #define    X_CORNER    -1.0
  1806. #define    Y_CORNER    -1.0
  1807. #define    WIDTH         2.0
  1808.  
  1809. /* hashing function to get a seed for the random number generator */
  1810. #define    hash_rand(A,B,C)    ( ( ((A)<<(23-(C))) + ((B)<<(15-(C)))\
  1811.                   + ((A)<<(7-(C))) ) & 0xffff )
  1812.  
  1813. static    long    num_pts ;
  1814. static  double    roughness ;
  1815.  
  1816. main(argc,argv)
  1817. int argc ;
  1818. char *argv[] ;
  1819. {
  1820.     COORD4  back_color, obj_color ;
  1821.     COORD4  center, light ;
  1822.     COORD4  from, at, up ;
  1823.     double  ratio ;
  1824.  
  1825.  
  1826.     /* output viewpoint */
  1827.     SET_COORD( from, -1.6, 1.6, 1.7 ) ;
  1828.     SET_COORD( at, 0.0, 0.0, 0.0 ) ;
  1829.     SET_COORD( up, 0.0, 0.0, 1.0 ) ;
  1830.     lib_output_viewpoint( &from, &at, &up, 45.0, 0.5, 512, 512 ) ;
  1831.  
  1832.     /* output background color - UNC sky blue */
  1833.     SET_COORD( back_color, 0.078, 0.361, 0.753 ) ;
  1834.     lib_output_background_color( &back_color ) ;
  1835.  
  1836.     /* output light sources */
  1837.     SET_COORD( light, -100.0, -100.0, 100.0 ) ;
  1838.     lib_output_light( &light ) ;
  1839.  
  1840.     /* set up crystal sphere color - clear white */
  1841.     SET_COORD( obj_color, 1.0, 1.0, 1.0 ) ;
  1842.     lib_output_color( &obj_color, 0.1, 0.9, 100.0, 0.9, 1.5 ) ;
  1843.  
  1844.     /* output crystal spheres */
  1845.     SET_COORD4( center, -0.8, 0.8, 1.00, 0.17 ) ;
  1846.     create_spheres( ¢er ) ;
  1847.  
  1848.     /* set up mountain color - grey */
  1849.     SET_COORD( obj_color, 0.5, 0.45, 0.35 ) ;
  1850.     lib_output_color( &obj_color, 1.0, 0.0, 0.0, 0.0, 0.0 ) ;
  1851.  
  1852.     /* grow mountain */
  1853.     num_pts = 1<<SIZE_FACTOR ;
  1854.     ratio = 2.0 /
  1855.         exp( (double)( log( (double)2.0 ) / (FRACTAL_DIMENSION-1.0) ) ) ;
  1856.     roughness = sqrt( (double)( SQR(ratio) - 1.0 ) ) ;
  1857.     grow_mountain( num_pts, 0, 0, 0.0, 0.0, 0.0, 0.0 ) ;
  1858. }
  1859.  
  1860.  
  1861. /* create a pyramid of crystal spheres */
  1862. create_spheres( center )
  1863. COORD4    *center ;
  1864. {
  1865.     double  angle ;
  1866.     COORD4  axis, new_pt, pt, sphere ;
  1867.     long    i ;
  1868.     MATRIX  mx ;
  1869.  
  1870.  
  1871.     SET_COORD( axis, 1.0, 1.0, 0.0 ) ;
  1872.     lib_normalize_coord3( &axis ) ;
  1873.     angle = acos( (double)( -1.0/3.0 ) ) ;
  1874.  
  1875.     /* set center of pyramid and radius */
  1876.     SET_COORD4( pt, 0.0, 0.0, center->w * sqrt( (double)( 3.0/2.0 ) ), 0.0 ) ;
  1877.  
  1878.     COPY_COORD( sphere, pt ) ;
  1879.     ADD2_COORD( sphere, *center ) ;
  1880.     sphere.w = center->w ;
  1881.     lib_output_sphere( &sphere, OUTPUT_FORMAT ) ;
  1882.  
  1883.     lib_create_axis_rotate_matrix( mx, &axis, angle ) ;
  1884.     lib_transform_coord( &new_pt, &pt, mx ) ;
  1885.  
  1886.     for ( i = 0 ; i < 3 ; ++i ) {
  1887.     lib_create_rotate_matrix( mx, Z_AXIS, (double)i * 2.0 * PI / 3.0 ) ;
  1888.     lib_transform_coord( &sphere, &new_pt, mx ) ;
  1889.     ADD2_COORD( sphere, *center ) ;
  1890.     sphere.w = center->w ;
  1891.     lib_output_sphere( &sphere, OUTPUT_FORMAT ) ;
  1892.     }
  1893. }
  1894.  
  1895.  
  1896.  
  1897.  
  1898. /*
  1899.  * Build mountain section.  If at width > 1, split quadrilateral into four
  1900.  * parts.  Else if at width == 1, output quadrilateral as two triangles.
  1901.  */
  1902. grow_mountain( width, ll_x, ll_y, ll_fz, lr_fz, ur_fz, ul_fz )
  1903. long    width ;
  1904. long    ll_x ;
  1905. long    ll_y ;
  1906. double    ll_fz ;
  1907. double    lr_fz ;
  1908. double    ur_fz ;
  1909. double    ul_fz ;
  1910. {
  1911.     long    half_width, iz ;
  1912.     double  l_fx, r_fx, l_fy, u_fy ;
  1913.     double  lower_fz, right_fz, upper_fz, left_fz, middle_fz ;
  1914.     long    num_tri, num_tri_vert, num_vert ;
  1915.     double  rise_height, hside_length ;
  1916.     COORD4  tri_vert[3] ;
  1917.  
  1918.  
  1919.     if ( width == 1 ) {
  1920.     /* calculate x and y coordinates of corners */
  1921.     l_fx = X_CORNER + (double)ll_x * WIDTH / (double)num_pts ;
  1922.     r_fx = X_CORNER + (double)(ll_x+1) * WIDTH / (double)num_pts ;
  1923.     l_fy = Y_CORNER + (double)ll_y * WIDTH / (double)num_pts ;
  1924.     u_fy = Y_CORNER + (double)(ll_y+1) * WIDTH / (double)num_pts ;
  1925.  
  1926.     /* output two triangles for section */
  1927.     for ( num_tri = 0 ; num_tri < 2 ; ++num_tri ) {
  1928.         for ( num_vert = 0 ; num_vert < 3 ; ++num_vert ) {
  1929.         num_tri_vert = ( num_vert + num_tri * 2 ) % 4 ;
  1930.         if ( num_tri_vert == 0 ) {
  1931.             SET_COORD( tri_vert[num_vert], l_fx, l_fy, ll_fz ) ;
  1932.         }
  1933.         else if ( num_tri_vert == 1 ) {
  1934.             SET_COORD( tri_vert[num_vert], r_fx, l_fy, lr_fz ) ;
  1935.         }
  1936.         else if ( num_tri_vert == 2 ) {
  1937.             SET_COORD( tri_vert[num_vert], r_fx, u_fy, ur_fz ) ;
  1938.         }
  1939.         else {
  1940.             SET_COORD( tri_vert[num_vert], l_fx, u_fy, ul_fz ) ;
  1941.         }
  1942.         }
  1943.         lib_output_polygon( 3, tri_vert ) ;
  1944.     }
  1945.     }
  1946.  
  1947.     else {
  1948.     /* subdivide edges and move in z direction */
  1949.     half_width = width>>1 ;
  1950.     hside_length = (double)half_width * WIDTH / (double)num_pts ;
  1951.     rise_height = hside_length * roughness ;
  1952.  
  1953.     /* for each midpoint, find z */
  1954.     iz = MOUNTAIN_NO + hash_rand( ll_x + half_width, ll_y, SIZE_FACTOR ) ;
  1955.     lower_fz = ( ll_fz + lr_fz ) / 2.0 +
  1956.                     rise_height * lib_gauss_rand( iz ) ;
  1957.     iz = MOUNTAIN_NO +
  1958.         hash_rand( ll_x + width, ll_y + half_width, SIZE_FACTOR ) ;
  1959.     right_fz = ( lr_fz + ur_fz ) / 2.0 +
  1960.                     rise_height * lib_gauss_rand( iz ) ;
  1961.     iz = MOUNTAIN_NO +
  1962.         hash_rand( ll_x + half_width, ll_y + width, SIZE_FACTOR ) ;
  1963.     upper_fz = ( ur_fz + ul_fz ) / 2.0 +
  1964.                     rise_height * lib_gauss_rand( iz ) ;
  1965.     iz = MOUNTAIN_NO + hash_rand( ll_x, ll_y + half_width, SIZE_FACTOR ) ;
  1966.     left_fz  = ( ul_fz + ll_fz ) / 2.0 +
  1967.                     rise_height * lib_gauss_rand( iz ) ;
  1968.     iz = MOUNTAIN_NO +
  1969.         hash_rand( ll_x + half_width, ll_y + half_width, SIZE_FACTOR ) ;
  1970.     middle_fz = ( ll_fz + lr_fz + ur_fz + ul_fz ) / 4.0 +
  1971.                 1.4142136 * rise_height * lib_gauss_rand( iz ) ;
  1972.  
  1973.     /* check subsections for subdivision or output */
  1974.     grow_mountain( half_width, ll_x, ll_y,
  1975.                     ll_fz, lower_fz, middle_fz, left_fz ) ;
  1976.     grow_mountain( half_width, ll_x+half_width, ll_y,
  1977.                     lower_fz, lr_fz, right_fz, middle_fz ) ;
  1978.     grow_mountain( half_width, ll_x+half_width, ll_y+half_width,
  1979.                     middle_fz, right_fz, ur_fz, upper_fz ) ;
  1980.     grow_mountain( half_width, ll_x, ll_y+half_width,
  1981.                     left_fz, middle_fz, upper_fz, ul_fz ) ;
  1982.     }
  1983. }
  1984. @//E*O*F mountain.c//
  1985. chmod u=rw,g=r,o= mountain.c
  1986. echo x - rings.c
  1987. sed 's/^@//' > "rings.c" <<'@//E*O*F rings.c//'
  1988. /*
  1989.  * rings.c - Create objects with 6 pentagonal rings which connect the midpoints
  1990.  *     of the edges of a dodecahedron.  A pyramid of these objects is formed,
  1991.  *     which the viewer looks upon from the point.  A plane is placed behind
  1992.  *     the pyramid for shadows.  No object is clipped.  Three light sources.
  1993.  *
  1994.  * Version:  2.2 (11/17/87)
  1995.  * Author:  Eric Haines, 3D/Eye, Inc.
  1996.  *
  1997.  * SIZE_FACTOR determines the number of objects output.
  1998.  *     Each object has 30 cylinders and 30 spheres.
  1999.  *     Total objects = SF*SF + (SF-1)*(SF-1) + ... + 1 plus 1 backdrop square.
  2000.  *     formula for # of spheres or cylinders = 5*SF*(SF+1)*(2*SF+1)
  2001.  *
  2002.  *     SIZE_FACTOR    # spheres    # cylinders    # squares
  2003.  *        1            30              30         1
  2004.  *        2           150             150         1
  2005.  *        3           420             420         1
  2006.  *
  2007.  *        7          4200            4200         1
  2008.  */
  2009.  
  2010. #include <stdio.h>
  2011. #include <math.h>
  2012. #include <memory.h>
  2013. #include "def.h"
  2014. #include "lib.h"
  2015.  
  2016. #define    OUTPUT_FORMAT        OUTPUT_CURVES
  2017. #define    SIZE_FACTOR        7
  2018.  
  2019. /* if spread out is > 1, succeeding layers spread out more */
  2020. #define    SPREAD_OUT        1
  2021.  
  2022. main(argc,argv)
  2023. int argc ;
  2024. char *argv[] ;
  2025. {
  2026.     COORD4  base_pt, apex_pt, offset ;
  2027.     COORD4  wall[4], dodec[30] ;
  2028.     COORD4  from, at, up ;
  2029.     COORD4  wvec, light ;
  2030.     COORD4  back_color, ring_color[6] ;
  2031.     long    prev_elem ;
  2032.     long    num_elem ;
  2033.     long    num_depth, num_objx, num_objz ;
  2034.     double  radius ;
  2035.     double  spread, y_diff, xz_diff ;
  2036.  
  2037.  
  2038.     radius = 0.07412 ;    /* cone and sphere radius */
  2039.  
  2040.     /* calculate spread of objects */
  2041.     spread = 1 / sin( (double)( PI/8.0 ) ) ;
  2042.     if ( SPREAD_OUT <= spread ) {
  2043.     y_diff = spread / SPREAD_OUT ;
  2044.     xz_diff = 1.0 ;
  2045.     }
  2046.     else {
  2047.     y_diff = 1.0 ;
  2048.     xz_diff = SPREAD_OUT / spread ;
  2049.     }
  2050.  
  2051.     /* output viewpoint */
  2052.     SET_COORD( from, -1.0, -spread, 0.5 ) ;
  2053.     SET_COORD( at, from.x, from.y + 1.0, from.z ) ;
  2054.     SET_COORD( up, 0.0, 0.0, 1.0 ) ;
  2055.     lib_output_viewpoint( &from, &at, &up, 45.0, 1.0, 512, 512 ) ;
  2056.  
  2057.     /* output background color - UNC sky blue */
  2058.     /* note that the background color should never be seen */
  2059.     SET_COORD( back_color, 0.078, 0.361, 0.753 ) ;
  2060.     lib_output_background_color( &back_color ) ;
  2061.  
  2062.     /* output light source */
  2063.     SET_COORD( light, 3.0, -spread, 3.0 ) ;
  2064.     lib_output_light( &light ) ;
  2065.     SET_COORD( light, -4.0, -spread, 1.0 ) ;
  2066.     lib_output_light( &light ) ;
  2067.     SET_COORD( light, 2.0, -spread, -4.0 ) ;
  2068.     lib_output_light( &light ) ;
  2069.  
  2070.     /* output wall polygon - white */
  2071.     SET_COORD( back_color, 1.0, 1.0, 1.0 ) ;
  2072.     lib_output_color( &back_color, 1.0, 0.0, 0.0, 0.0, 0.0 ) ;
  2073.     /* just spans 45 degree view + 1% */
  2074.     wvec.y = y_diff * ( SIZE_FACTOR + 1 ) ;
  2075.     wvec.x = wvec.z = 1.01 * ( wvec.y - from.y ) * tan( PI / 8.0 ) ;
  2076.     SET_COORD( wall[0],  wvec.x+from.x, wvec.y,  wvec.z+from.z ) ;
  2077.     SET_COORD( wall[1], -wvec.x+from.x, wvec.y,  wvec.z+from.z ) ;
  2078.     SET_COORD( wall[2], -wvec.x+from.x, wvec.y, -wvec.z+from.z ) ;
  2079.     SET_COORD( wall[3],  wvec.x+from.x, wvec.y, -wvec.z+from.z ) ;
  2080.     lib_output_polygon( 4, wall ) ;
  2081.  
  2082.     /* set up ring colors - RGB and complements */
  2083.     SET_COORD( ring_color[0], 1.0, 0.0, 0.0 ) ;
  2084.     SET_COORD( ring_color[1], 0.0, 1.0, 0.0 ) ;
  2085.     SET_COORD( ring_color[2], 0.0, 0.0, 1.0 ) ;
  2086.     SET_COORD( ring_color[3], 0.0, 1.0, 1.0 ) ;
  2087.     SET_COORD( ring_color[4], 1.0, 0.0, 1.0 ) ;
  2088.     SET_COORD( ring_color[5], 1.0, 1.0, 0.0 ) ;
  2089.  
  2090.     create_dodec( radius, dodec ) ;
  2091.     /* radius of osculating cylinders and spheres (no derivation given) */
  2092.     base_pt.w = apex_pt.w = radius ;
  2093.  
  2094.     for ( num_depth = 0 ; num_depth < SIZE_FACTOR ; ++num_depth ) {
  2095.     offset.y = y_diff * (double)(num_depth+1) ;
  2096.     for ( num_objz = 0 ; num_objz <= num_depth ; ++num_objz ) {
  2097.         offset.z = xz_diff * (double)(2*num_objz - num_depth) ;
  2098.         for ( num_objx = 0 ; num_objx <= num_depth ; ++num_objx ) {
  2099.         offset.x = xz_diff * (double)(2*num_objx - num_depth) ;
  2100.         for ( num_elem = 0 ; num_elem < 30 ; ++num_elem ) {
  2101.             COPY_COORD( base_pt, dodec[num_elem] ) ;
  2102.             ADD2_COORD( base_pt, offset ) ;
  2103.             if ( num_elem%5 == 0 ) {
  2104.             prev_elem = num_elem + 4 ;
  2105.             /* new ring beginning - output color */
  2106.             lib_output_color( &ring_color[num_elem/5]
  2107.                     , 0.5
  2108.                     , 0.5, 3.0
  2109.                     , 0.0, 0.0
  2110.                     ) ;
  2111.             }
  2112.             else {
  2113.             prev_elem = num_elem - 1 ;
  2114.             }
  2115.             COPY_COORD( apex_pt, dodec[prev_elem] ) ;
  2116.             ADD2_COORD( apex_pt, offset ) ;
  2117.  
  2118.             lib_output_cylcone( &base_pt, &apex_pt, OUTPUT_FORMAT ) ;
  2119.             lib_output_sphere( &base_pt, OUTPUT_FORMAT ) ;
  2120.         }
  2121.         }
  2122.     }
  2123.     }
  2124. }
  2125.  
  2126. /* Create the set of 30 points needed to generate the rings */
  2127. create_dodec( minor_radius, vertex )
  2128. double    minor_radius ;
  2129. COORD4    vertex[30] ;
  2130. {
  2131.     long    num_vertex, num_pentagon ;
  2132.     COORD4  temp_vertex ;
  2133.     MATRIX  x_matrix, z_matrix ;
  2134.     double  scale, x_rotation, z_rotation ;
  2135.  
  2136.  
  2137.     /* scale object to fit in a sphere of radius 1 */
  2138.  
  2139.     scale = 1.0 / ( 1.0 + minor_radius ) ;
  2140.     /*
  2141.      * define one pentagon as on the XY plane, with points starting along +X
  2142.      * and N fifths of the way around the Z axis.
  2143.      */
  2144.     for ( num_vertex = 0 ; num_vertex < 5 ; ++num_vertex ) {
  2145.     vertex[num_vertex].x = scale * cos( (double)num_vertex * 2.0*PI/5.0 ) ;
  2146.     vertex[num_vertex].y = scale * sin( (double)num_vertex * 2.0*PI/5.0 ) ;
  2147.     vertex[num_vertex].z = 0.0 ;
  2148.     vertex[num_vertex].w = 1.0 ;
  2149.     }
  2150.  
  2151.     /*
  2152.      * find the rotation angle (in radians) along the X axis:
  2153.      * angle between two adjacent dodecahedron faces.
  2154.      */
  2155.     x_rotation = 2.0 *
  2156.         acos( cos( (double)(PI/3.0) ) / sin( (double)(PI/5.0) ) ) ;
  2157.     lib_create_rotate_matrix( x_matrix, X_AXIS, x_rotation ) ;
  2158.  
  2159.     /*
  2160.      * Find each of the other 5 pentagons:  rotate along the X axis,
  2161.      * then rotate on the Z axis.
  2162.      */
  2163.     for ( num_pentagon = 1 ; num_pentagon < 6 ; ++num_pentagon ) {
  2164.     /*
  2165.      * find the rotation angle (in radians) along the Z axis:
  2166.      * 1/10th plus N fifths of the way around * 2 * PI.
  2167.      */
  2168.     z_rotation = PI*( 2.0*(double)(num_pentagon-1)+1.0 ) / 5.0 ;
  2169.     lib_create_rotate_matrix( z_matrix, Z_AXIS, z_rotation ) ;
  2170.  
  2171.     for ( num_vertex = 0 ; num_vertex < 5 ; ++num_vertex ) {
  2172.  
  2173.         lib_transform_coord( &temp_vertex
  2174.                    , &vertex[num_vertex]
  2175.                    , x_matrix
  2176.                    ) ;
  2177.  
  2178.         lib_transform_coord( &vertex[5*num_pentagon+num_vertex]
  2179.                    , &temp_vertex
  2180.                    , z_matrix
  2181.                    ) ;
  2182.     }
  2183.     }
  2184. }
  2185. @//E*O*F rings.c//
  2186. chmod u=rw,g=r,o= rings.c
  2187. echo x - tetra.c
  2188. sed 's/^@//' > "tetra.c" <<'@//E*O*F tetra.c//'
  2189. /*
  2190.  * tetra.c - Create a tetrahedral pyramid.  This environment is based on the
  2191.  *     scene used by Glassner ("Space Subdivision for Fast Ray Tracing," IEEE
  2192.  *     CG&A, October 1984) and Kay & Kajiya ("Ray Tracing Complex Scenes,"
  2193.  *     SIGGRAPH '86 Proceedings) for testing their ray tracers.  No polygons
  2194.  *     are clipped.  One light source.
  2195.  *
  2196.  * Version:  2.2 (11/17/87)
  2197.  * Author:  Eric Haines, 3D/Eye, Inc.
  2198.  *
  2199.  * Note:  the view and light positions are the same (after transformation to
  2200.  *     a different set of world coordinates) as used by Kay & Kajiya,
  2201.  *     courtesy of Tim Kay.  For some reason, the number of shadow rays
  2202.  *     generated is different (Kay gets 34K, I get 46K).  One light source.
  2203.  *
  2204.  * SIZE_FACTOR determines the number of polygons output.
  2205.  *     Total triangular polygons = 4**SF
  2206.  *
  2207.  *     SIZE_FACTOR    # triangles
  2208.  *        1             4
  2209.  *        2            16
  2210.  *        3            64
  2211.  *
  2212.  *        6          4096
  2213.  */
  2214.  
  2215. #include <stdio.h>
  2216. #include <math.h>
  2217. #include <memory.h>
  2218. #include "def.h"
  2219. #include "lib.h"
  2220.  
  2221. #define    SIZE_FACTOR        6
  2222.  
  2223.  
  2224. main(argc,argv)
  2225. int argc ;
  2226. char *argv[] ;
  2227. {
  2228.     COORD4  back_color, tetra_color ;
  2229.     COORD4  center_pt, light ;
  2230.     COORD4  from, at, up ;
  2231.  
  2232.  
  2233.     /* output viewpoint */
  2234.     SET_COORD( from, 1.022846, -3.177154, -2.174512 ) ;
  2235.     SET_COORD( at, -0.004103, -0.004103, 0.216539 ) ;
  2236.     SET_COORD( up, -0.816497, -0.816497, 0.816497 ) ;
  2237.     lib_output_viewpoint( &from, &at, &up, 45.0, 1.0, 512, 512 ) ;
  2238.  
  2239.     /* output background color - UNC sky blue */
  2240.     SET_COORD( back_color, 0.078, 0.361, 0.753 ) ;
  2241.     lib_output_background_color( &back_color ) ;
  2242.  
  2243.     /* output light source */
  2244.     SET_COORD( light, 1.876066, -18.123936, -5.000422 ) ;
  2245.     lib_output_light( &light ) ;
  2246.  
  2247.     /* output tetrahedron color - red */
  2248.     SET_COORD( tetra_color, 1.0, 0.2, 0.2 ) ;
  2249.     lib_output_color( &tetra_color, 1.0, 0.0, 0.0, 0.0, 0.0 ) ;
  2250.  
  2251.     /* compute and output tetrahedral object */
  2252.     SET_COORD4( center_pt, 0.0, 0.0, 0.0, 1.0 ) ;
  2253.     create_tetra( SIZE_FACTOR, ¢er_pt ) ;
  2254. }
  2255.  
  2256.  
  2257. /* Create tetrahedrons recursively */
  2258. create_tetra( depth, center )
  2259. long    depth ;
  2260. COORD4    *center ;
  2261. {
  2262.     long    num_face, num_vert ;
  2263.     COORD4  face_pt[3], obj_pt[4], sub_center ;
  2264.     long    swap, vert_ord[3] ;
  2265.     long    x_dir, y_dir, z_dir ;
  2266.  
  2267.  
  2268.     if ( depth <= 1 ) {
  2269.     /* Output tetrahedron */
  2270.  
  2271.     /* find opposite corners of a cube which form a tetrahedron */
  2272.     for ( num_vert = 0, x_dir = -1 ; x_dir <= 1 ; x_dir += 2 ) {
  2273.         for ( y_dir = -1 ; y_dir <= 1 ; y_dir += 2 ) {
  2274.         for ( z_dir = -1 ; z_dir <= 1 ; z_dir += 2 ) {
  2275.             if ( x_dir*y_dir*z_dir == 1 ) {
  2276.             obj_pt[num_vert].x =
  2277.                     center->x + (double)x_dir * center->w ;
  2278.             obj_pt[num_vert].y =
  2279.                     center->y + (double)y_dir * center->w ;
  2280.             obj_pt[num_vert].z =
  2281.                     center->z + (double)z_dir * center->w ;
  2282.             ++num_vert ;
  2283.             }
  2284.         }
  2285.         }
  2286.     }
  2287.  
  2288.     /* find faces and output */
  2289.     for ( num_face = 0 ; num_face < 4 ; ++num_face ) {
  2290.         /* output order:
  2291.          *   face 0:  points 0 1 2
  2292.          *   face 1:  points 3 2 1
  2293.          *   face 2:  points 2 3 0
  2294.          *   face 3:  points 1 0 3
  2295.          */
  2296.         for ( num_vert = 0 ; num_vert < 3 ; ++num_vert ) {
  2297.         vert_ord[num_vert] = (num_face + num_vert) % 4 ;
  2298.         }
  2299.         if ( num_face%2 == 1 ) {
  2300.         swap = vert_ord[0] ;
  2301.         vert_ord[0] = vert_ord[2] ;
  2302.         vert_ord[2] = swap ;
  2303.         }
  2304.  
  2305.         for ( num_vert = 0 ; num_vert < 3 ; ++num_vert ) {
  2306.         COPY_COORD( face_pt[num_vert], obj_pt[vert_ord[num_vert]] ) ;
  2307.         }
  2308.         lib_output_polygon( 3, face_pt ) ;
  2309.     }
  2310.     }
  2311.  
  2312.     else {
  2313.     /* Create sub-tetrahedra */
  2314.  
  2315.     /* find opposite corners of a cube to form sub-tetrahedra */
  2316.     for ( x_dir = -1 ; x_dir <= 1 ; x_dir += 2 ) {
  2317.         for ( y_dir = -1 ; y_dir <= 1 ; y_dir += 2 ) {
  2318.         for ( z_dir = -1 ; z_dir <= 1 ; z_dir += 2 ) {
  2319.             if ( x_dir*y_dir*z_dir == 1 ) {
  2320.             sub_center.x =
  2321.                 center->x + (double)x_dir * center->w / 2.0 ;
  2322.             sub_center.y =
  2323.                 center->y + (double)y_dir * center->w / 2.0 ;
  2324.             sub_center.z =
  2325.                 center->z + (double)z_dir * center->w / 2.0 ;
  2326.             sub_center.w = center->w / 2.0 ;
  2327.  
  2328.             create_tetra( depth-1, &sub_center ) ;
  2329.             }
  2330.         }
  2331.         }
  2332.     }
  2333.     }
  2334. }
  2335. @//E*O*F tetra.c//
  2336. chmod u=rw,g=r,o= tetra.c
  2337. echo x - tree.c
  2338. sed 's/^@//' > "tree.c" <<'@//E*O*F tree.c//'
  2339. /*
  2340.  * tree.c - Creates a tree using Aono & Kunii's generation method.
  2341.  *     (See IEEE CG&A May 1984).  A square polygon is placed beneath the
  2342.  *     tree to act as a field.  No tree branch is clipped.  Seven light sources.
  2343.  *
  2344.  * Version:  2.2 (11/17/87)
  2345.  * Author:  Eric Haines, 3D/Eye, Inc.
  2346.  *
  2347.  * SIZE_FACTOR determines the number of objects output.
  2348.  *     Total objects = 2**(SF+1)-1 cones and spheres + 1 square polygon.
  2349.  *
  2350.  *     SIZE_FACTOR    # spheres       # cones    # squares
  2351.  *        1             3               3         1
  2352.  *        2             7               7         1
  2353.  *        3            15              15         1
  2354.  *
  2355.  *       11          4095            4095         1
  2356.  */
  2357.  
  2358. #include <stdio.h>
  2359. #include <math.h>
  2360. #include <memory.h>
  2361. #include "def.h"
  2362. #include "lib.h"
  2363.  
  2364. #define    OUTPUT_FORMAT        OUTPUT_CURVES
  2365. #define    SIZE_FACTOR        11
  2366.  
  2367. /* the following affect the shape of the tree */
  2368. #define    BR_ANGLE_0        40.0
  2369. #define    BR_ANGLE_1        25.0
  2370. #define    BR_CONTR_0        0.65
  2371. #define    BR_CONTR_1        0.70
  2372. #define    BR_DIAMETER        0.67
  2373. #define    DIV_ANGLE        140.0
  2374. #define    WIDTH_HEIGHTH_RATIO    0.15
  2375.  
  2376.  
  2377. static    MATRIX    rst_mx[2] ;
  2378.  
  2379.  
  2380. main(argc,argv)
  2381. int argc ;
  2382. char *argv[] ;
  2383. {
  2384.     COORD4  field[4] ;
  2385.     COORD4  from, at, up ;
  2386.     COORD4  light ;
  2387.     COORD4  back_color, tree_color ;
  2388.  
  2389.  
  2390.     /* output viewpoint */
  2391.     SET_COORD( from, 4.5, 0.4, 2.0 ) ;
  2392.     SET_COORD( at, 0.0, 0.0, 1.5 ) ;
  2393.     SET_COORD( up, 0.0, 0.0, 1.0 ) ;
  2394.     lib_output_viewpoint( &from, &at, &up, 45.0, 1.0, 512, 512 ) ;
  2395.  
  2396.     /* output background color - UNC sky blue */
  2397.     SET_COORD( back_color, 0.078, 0.361, 0.753 ) ;
  2398.     lib_output_background_color( &back_color ) ;
  2399.  
  2400.     /* output light source */
  2401.     SET_COORD( light, -5.0, 5.0, 50.0 ) ;
  2402.     lib_output_light( &light ) ;
  2403.     SET_COORD( light, 30.0, -30.0, 30.0 ) ;
  2404.     lib_output_light( &light ) ;
  2405.     SET_COORD( light, -40.0, -30.0, 20.0 ) ;
  2406.     lib_output_light( &light ) ;
  2407.     SET_COORD( light, 10.0, 30.0, 40.0 ) ;
  2408.     lib_output_light( &light ) ;
  2409.     SET_COORD( light, -30.0, 40.0, 10.0 ) ;
  2410.     lib_output_light( &light ) ;
  2411.     SET_COORD( light, 50.0, 25.0, 20.0 ) ;
  2412.     lib_output_light( &light ) ;
  2413.     SET_COORD( light, -10.0, -60.0, 30.0 ) ;
  2414.     lib_output_light( &light ) ;
  2415.  
  2416.     /* output field polygon - green */
  2417.     SET_COORD( back_color, 0.2, 0.7, 0.2 ) ;
  2418.     lib_output_color( &back_color, 1.0, 0.0, 0.0, 0.0, 0.0 ) ;
  2419.     SET_COORD( field[0],  50.0,  50.0, 0.0 ) ;
  2420.     SET_COORD( field[1], -50.0,  50.0, 0.0 ) ;
  2421.     SET_COORD( field[2], -50.0, -50.0, 0.0 ) ;
  2422.     SET_COORD( field[3],  50.0, -50.0, 0.0 ) ;
  2423.     lib_output_polygon( 4, field ) ;
  2424.  
  2425.     /* set up tree color - brown */
  2426.     SET_COORD( tree_color, 0.55, 0.4, 0.2 ) ;
  2427.     lib_output_color( &tree_color, 1.0, 0.0, 0.0, 0.0, 0.0 ) ;
  2428.  
  2429.     /* create tree */
  2430.     create_tree() ;
  2431. }
  2432.  
  2433.  
  2434. /*
  2435.  * Set up matrices for growth of each branch with respect to the
  2436.  * parent branch, then grow each branch.
  2437.  */
  2438. create_tree()
  2439. {
  2440.     double  branch_angle, branch_contraction, divergence ;
  2441.     long    i ;
  2442.     MATRIX  ident_mx, temp1_mx, temp2_mx, tempr_mx, tempst_mx ;
  2443.  
  2444.  
  2445.     for ( i = 0 ; i < 2 ; ++i ) {
  2446.     if ( i == 0 ) {
  2447.         branch_angle = BR_ANGLE_0 ;
  2448.         divergence = 90.0 ;
  2449.         branch_contraction = BR_CONTR_0 ;
  2450.     }
  2451.     else {
  2452.         branch_angle = BR_ANGLE_1 ;
  2453.         divergence = DIV_ANGLE + 90.0 ;
  2454.         branch_contraction = BR_CONTR_1 ;
  2455.     }
  2456.  
  2457.     /* rotate along X axis by branching angle */
  2458.     lib_create_rotate_matrix( temp1_mx, X_AXIS, branch_angle*PI/180.0 ) ;
  2459.  
  2460.     /* rotate along Z axis by divergence angle */
  2461.     lib_create_rotate_matrix( temp2_mx, Z_AXIS, divergence*PI/180.0 ) ;
  2462.  
  2463.     lib_matrix_multiply( tempr_mx, temp1_mx, temp2_mx ) ;
  2464.  
  2465.     /* include translation of branch, scaled */
  2466.     lib_create_identity_matrix( tempst_mx ) ;
  2467.     tempst_mx[0][0] = tempst_mx[1][1] = tempst_mx[2][2] =
  2468.                             branch_contraction ;
  2469.     tempst_mx[3][2] = 1.0 ;
  2470.  
  2471.     /* concatenate */
  2472.     lib_matrix_multiply( rst_mx[i], tempr_mx, tempst_mx ) ;
  2473.     }
  2474.  
  2475.     /* set up initial matrix */
  2476.     lib_create_identity_matrix( ident_mx ) ;
  2477.     grow_tree( ident_mx, 1.0, SIZE_FACTOR ) ;
  2478. }
  2479.  
  2480.  
  2481. /* grow tree branches recursively */
  2482. grow_tree( cur_mx, scale, depth )
  2483. MATRIX    cur_mx ;
  2484. double    scale ;
  2485. long    depth ;
  2486. {
  2487.     COORD4  apex, base, vec ;
  2488.     long    i ;
  2489.     MATRIX  new_mx ;
  2490.  
  2491.  
  2492.     /* output branch */
  2493.     SET_COORD4( vec, 0.0, 0.0, 0.0, 1.0 ) ;
  2494.     lib_transform_coord( &base, &vec, cur_mx ) ;
  2495.     base.w = scale * WIDTH_HEIGHTH_RATIO ;
  2496.  
  2497.     SET_COORD4( vec, 0.0, 0.0, 1.0, 1.0 ) ;
  2498.     lib_transform_coord( &apex, &vec, cur_mx ) ;
  2499.     apex.w = base.w * BR_DIAMETER ;
  2500.  
  2501.     lib_output_cylcone( &base, &apex, OUTPUT_FORMAT ) ;
  2502.     lib_output_sphere( &apex, OUTPUT_FORMAT ) ;
  2503.  
  2504.     if ( depth > 0 ) {
  2505.     --depth ;
  2506.  
  2507.     for ( i = 0; i < 2; ++i ) {
  2508.         lib_matrix_multiply( new_mx, rst_mx[i], cur_mx ) ;
  2509.         grow_tree( new_mx, scale * BR_DIAMETER, depth ) ;
  2510.     }
  2511.     }
  2512. }
  2513. @//E*O*F tree.c//
  2514. chmod u=rw,g=r,o= tree.c
  2515.  
  2516. exit 0
  2517.  
  2518.         
  2519.       
  2520.  
  2521.  
  2522. From saponara@tcgould.tn.cornell.edu Tue Sep  6 10:01:53 1988
  2523. Path: seismo!uunet!husc6!mailrus!cornell!batcomputer!saponara
  2524. From: saponara@batcomputer.tn.cornell.edu (John Saponara)
  2525. Newsgroups: comp.graphics
  2526. Subject: Re: Haine's NFF Package:        Part 01/01
  2527. Message-ID: <6220@batcomputer.tn.cornell.edu>
  2528. Date: 6 Sep 88 14:01:53 GMT
  2529. References: <2684@uoregon.uoregon.edu>
  2530. Reply-To: saponara@tcgould.tn.cornell.edu (Eric Haines, actually)
  2531. Organization: 3D/Eye Inc (not Cornell, actually)
  2532. Lines: 249
  2533.  
  2534. In article <2684@uoregon.uoregon.edu> markv@drizzle.UUCP (Mark VandeWettering) writes:
  2535. >
  2536. >
  2537. >This is as it was posted to comp.graphics AGES ago.  Have fun.  If
  2538. >someone figures out why "gears" turns out funny on my raytracer, let me
  2539. >know, I am stumped.
  2540.  
  2541. One possibility is that you've got an old version of gears.c.  A bug that
  2542. K.R. Subramanian pointed out to me was that the gear polygons overlap, which
  2543. causes refraction to be pretty ill-defined.
  2544.  
  2545. Attached are the patches to bring your posted version of the SPD package up
  2546. to version 2.4.  Note that the one available on netlib is at 2.4, so does
  2547. not need these patches.
  2548.  
  2549. Eric Haines (not John Saponara - do you believe me or the computer?)
  2550.  
  2551.  
  2552. *** old/README
  2553. --- new/README
  2554. 4c4
  2555. < Version 2.2, as of 11/17/87
  2556. ---
  2557. > Version 2.4, as of 5/1/88
  2558. 17a18,21
  2559. > Version 2.3 released March, 1988 - corrected gears.c to avoid interpenetration,
  2560. >     corrected and added further instructions and global statistics for ray
  2561. >     tracing to README.
  2562. > Version 2.4 released May, 1988 - fixed hashing function for mountain.c.
  2563. 55a60,63
  2564. >     The images for these databases and other information about them can be
  2565. > found in "A Proposal for Standard Graphics Environments," IEEE Computer
  2566. > Graphics & Applications, November 1987, pages 3-5.  A corrected image of the
  2567. > tree appears in IEEE CG&A, January 1987, page 18.
  2568. 56a65,69
  2569. >     At present, the SPD package is available for the IBM PC on 360K 5.25"
  2570. > floppy for $5 from:  MicroDoc, c/o F.W. Pospeschil, 3108 Jackson Street,
  2571. > Bellevue, Nebraska  68005.
  2572. 138c151
  2573. < background      0%         7%         47%          0%         81%         35%
  2574. ---
  2575. > background      0%         7%         34%          0%         81%         35%
  2576. 141,142d153
  2577. < ave tree size  1.79       3.02        3.71        2.19        1.00        1.00
  2578. < ave light rays 3.39       6.43        0.80        4.09        0.18        4.17
  2579. 143a155,159
  2580. > eye hit rays 263169     245532      173422      263169       49806      170134
  2581. > reflect rays 175616     305561      355355      316621           0           0
  2582. > refract rays      0     208153      355355           0           0           0
  2583. > shadow rays  954544    2126105      362657     1087366       46150     1099748
  2584. 171,176c187,191
  2585. < percentage of background color (empty space) seen directly by the eye.  Note
  2586. < that any information in units of pixels is view dependent, and so is for the
  2587. < view specified.  "ave tree size" is the average number of rays in a ray tree.
  2588. < "ave light rays" is the average number of shadow testing rays formed per tree
  2589. < (note that if a surface is facing away from a light, or the background is hit,
  2590. < a light ray is not formed).  "K" means exactly 1000 (not 1024).
  2591. ---
  2592. > percentage of background color (empty space) seen directly by the eye for the
  2593. > given view.  It is calculated by "1 - ( eye hit rays/(513*513) )", since
  2594. > 513 x 513 rays are generated from the eye.  "specular" tells if there are
  2595. > reflective objects in the scene, and "transmitter" if there are transparent
  2596. > objects.
  2597. 177a193,200
  2598. >     "eye hit rays" is the number of rays from the eye which actually hit an
  2599. > object (i.e. not the background).  "reflect rays" is the total number of rays
  2600. > generated by reflection off of reflecting and transmitting surfaces.  "refract
  2601. > rays" is the number of rays generated by transmitting surfaces.  "shadow rays"
  2602. > is the sum total of rays shot towards the lights.  Note that if a surface is
  2603. > facing away from a light, or the background is hit, a light ray is not formed.
  2604. > The numbers given can vary noticeably from a given ray tracer, but should all
  2605. > be within about 10%.
  2606. 178a202,204
  2607. >     "K" means exactly 1000 (not 1024), with number rounded to the nearest K.
  2608. 341,344c367,369
  2609. <     corners (meaning that at least 513 x 513 eye rays will be created).
  2610. <     The four corner contributions are averaged to arrive at a pixel
  2611. <     value.  If this is not done, note this fact.  No pixel subdivision
  2612. <     is performed.
  2613. ---
  2614. >     corners (meaning that 513 x 513 eye rays will be created).  The four
  2615. >     corner contributions are averaged to arrive at a pixel value.  If this
  2616. >     is not done, note this fact.  No pixel subdivision is performed.
  2617. 348,352c373,377
  2618. <     5)  All rays hitting specular and transmitting objects spawn reflection
  2619. <     rays, unless the maximum ray depth was reached by the spawning ray.
  2620. <     No adaptive tree depth cutoff is allowed; that is, all rays must be
  2621. <     spawned (adaptive tree depth is a proven time saver and is also
  2622. <     dependent on the color model used).
  2623. ---
  2624. >     5)  All rays hitting only specular and transmitting objects spawn
  2625. >     reflection rays, unless the maximum ray depth was reached by the
  2626. >     spawning ray.  No adaptive tree depth cutoff is allowed; that is, all
  2627. >     rays must be spawned (adaptive tree depth is a proven time saver and
  2628. >     is also dependent on the color model used).
  2629. 355,358c380,383
  2630. <     the maximum ray depth was reached.  Transmitting rays should be
  2631. <     refracted (i.e. should not pass straight through an object).  If total
  2632. <     internal reflection of a ray occurs, then only a reflection ray is
  2633. <     generated at this node.
  2634. ---
  2635. >     the maximum ray depth was reached or total internal reflection occurs.
  2636. >     Transmitting rays should be refracted using Snell's (i.e. should not
  2637. >     pass straight through an object).  If total internal reflection occurs,
  2638. >     then only a reflection ray is generated at this node.
  2639. 360,361c385,386
  2640. <     7)  Assume no hierarchy is given with the database (for example, color
  2641. <     change cannot be used to signal a clustering).
  2642. ---
  2643. >     7)  A shadow ray is not generated if the surface normal points away from
  2644. >     the light.
  2645. 363c388,392
  2646. <     8)  Timing costs should be separated into at least two areas: preprocessing
  2647. ---
  2648. >     8)  Assume no hierarchy is given with the database (for example, color
  2649. >     change cannot be used to signal a clustering).  The ray tracing program
  2650. >     itself can create its own hierarchy, of course.
  2651. >     9)  Timing costs should be separated into at least two areas: preprocessing
  2652. 371c400
  2653. <     9)  Other timing costs which would be of interest is a breakdown of
  2654. ---
  2655. >     10) Other timing costs which would be of interest is a breakdown of
  2656. 389c418
  2657. < Kflops.  However, some HP hardware engineer told me that the HP 320 is twice
  2658. ---
  2659. > Kflops.  However, an HP hardware engineer told me that the HP 320 is twice
  2660. 396c425
  2661. < language used (i.e. optimized "C", single point precision in general).
  2662. ---
  2663. > language used (i.e. optimized "C", single precision in general).
  2664. 466c495
  2665. <   number of eye rays which hit background: 213219    [ 81% ]
  2666. ---
  2667. >   number of eye rays which hit background: 213363    [ 81% ]
  2668. 469c498
  2669. <   total number of shadow rays generated: 46262
  2670. ---
  2671. >   total number of shadow rays generated: 46150
  2672. 490,491c519,520
  2673. < environment).  Same question with the effects of moving light source positions
  2674. < along the line defined by the light and "lookat" positions.
  2675. ---
  2676. > environment).  Same question with the effects on the algorithms of moving light
  2677. > source positions along the line defined by the light and "lookat" positions.
  2678. 520,526c549,555
  2679. < Elmquist, Jeff Goldsmith, Donald Greenberg, Susan Spach, Rick Speer, John
  2680. < Wallace, and Louise Watson.  Other people who have freely offered their ideas
  2681. < and opinions on this project include Brian Barsky, Andrew Glassner, Roy Hall,
  2682. < Chip Hatfield, Tim Kay, John Recker, Paul Strauss, and Chan Verbeck.  These
  2683. < names are mentioned mostly as a listing of people interested in this idea.
  2684. < They do not necessarily agree (and in some cases strongly disagree) with the
  2685. < validity of the concept or the choice of databases.
  2686. ---
  2687. > Elmquist, Jeff Goldsmith, Donald Greenberg, Susan Spach, Rick Speer, K.R.
  2688. > Subramanian, John Wallace, and Louise Watson.  Other people who have freely
  2689. > offered their ideas and opinions on this project include Brian Barsky, Andrew
  2690. > Glassner, Roy Hall, Chip Hatfield, Tim Kay, John Recker, Paul Strauss, and Chan
  2691. > Verbeck.  These names are mentioned mostly as a listing of people interested in
  2692. > this idea.  They do not necessarily agree (and in some cases strongly disagree)
  2693. > with the validity of the concept or the choice of databases.
  2694. *** old/gears.c
  2695. --- new/gears.c
  2696. 6c6
  2697. <  *    Five light sources.
  2698. ---
  2699. >  *    Five light sources.  
  2700. 8c8
  2701. <  * Version:  2.2 (11/17/87)
  2702. ---
  2703. >  * Version:  2.3 (3/1?/88)
  2704. 33c33,41
  2705. < #define    EDGE_RATIO        0.1
  2706. ---
  2707. > /* the outer radius is made slightly smaller that the full radius to create
  2708. >  * a finite separation between intermeshing gears.  This gets rid of the bug
  2709. >  * of having two surfaces occupy exactly the same space.  Note that if these
  2710. >  * are changed, the gears may interpenetrate.
  2711. >  */
  2712. > #define    OUTER_EDGE_RATIO    0.995
  2713. > #define    INNER_EDGE_RATIO    0.9
  2714. > #define    EDGE_DIFF        ( 1.0 - INNER_EDGE_RATIO )
  2715. > /* ratio of width of gear to thickness */
  2716. 81c89
  2717. <     ( (double)SIZE_FACTOR - (double)(SIZE_FACTOR-1) * EDGE_RATIO / 2.0 ) ;
  2718. ---
  2719. >     ( (double)SIZE_FACTOR - (double)(SIZE_FACTOR-1) * EDGE_DIFF / 2.0 ) ;
  2720. 86c94
  2721. <     offset.x = offset.y = outer_radius * ( 2.0 - EDGE_RATIO ) ;
  2722. ---
  2723. >     offset.x = offset.y = outer_radius * ( 2.0 - EDGE_DIFF ) ;
  2724. 122,123c130,131
  2725. <                  outer_radius,
  2726. <                  (1.0 - EDGE_RATIO) * outer_radius,
  2727. ---
  2728. >                  OUTER_EDGE_RATIO * outer_radius,
  2729. >                  (1.0 - EDGE_DIFF) * outer_radius,
  2730. *** old/mountain.c
  2731. --- new/mountain.c
  2732. 7c7,15
  2733. <  * Version:  2.2 (11/17/87)
  2734. ---
  2735. >  *     NOTE: the hashing function used to generate the database originally is
  2736. >  *     faulty.  The function causes repetition to occur within the fractal
  2737. >  *     mountain (obviously not very fractal behavior!).  A new hashing function
  2738. >  *     is included immediately after the old one:  merely define NEW_HASH if
  2739. >  *     you want to use a good hashing function.  To perform ray tracing
  2740. >  *     comparison tests you should still use the old, faulty database (it may
  2741. >  *     have repetition, but it's still a good test image).
  2742. >  *     
  2743. >  * Version:  2.4 (5/1/88)
  2744. 26a35,37
  2745. > /* to use the corrected hashing function, uncomment this next line */
  2746. > /* #define NEW_HASH */
  2747. 41c52,56
  2748. < /* hashing function to get a seed for the random number generator */
  2749. ---
  2750. > #ifndef NEW_HASH
  2751. > /* Hashing function to get a seed for the random number generator. */
  2752. > /* This is the old, buggy hashing function - use it if you wish to
  2753. >  * obtain the same image as in the November 1987 IEEE CG&A article. */
  2754. 44a60,77
  2755. > #else
  2756. > /* New, corrected hashing function.  Use for a true fractal mountain */
  2757. > /* 134456 is M1 in routine lib_gauss_rand() */
  2758. > #define    hash_rand(A,B,C)    ( ( C <= 15 ) ?                \
  2759. >                       ( ABSOLUTE(            \
  2760. >                         ((A)<<(31-(C)))            \
  2761. >                       + ((B)<<(15-(C))) )        \
  2762. >                       % 134456 )            \
  2763. >                   :                    \
  2764. >                       ( ABSOLUTE(            \
  2765. >                         ((A)<<(31-(C)))            \
  2766. >                       + ((B)>>((C)-15)) )        \
  2767. >                       % 134456 )            \
  2768. >                   )
  2769. > #endif
  2770. 56d88
  2771.  
  2772.  
  2773.